Merge branch 'main' into dev-neighbours

This commit is contained in:
Winston Lowe 2026-01-18 11:27:19 -08:00
commit b41ccee4f9
43 changed files with 2167 additions and 792 deletions

76
.github/workflows/build.yml vendored Normal file
View file

@ -0,0 +1,76 @@
name: Build
on:
push:
pull_request:
jobs:
android:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: "temurin"
java-version: "17"
- uses: subosito/flutter-action@v2
with:
channel: "stable"
cache: true
- name: Cache Gradle
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('android/gradle/wrapper/gradle-wrapper.properties', 'android/build.gradle', 'android/settings.gradle', 'android/app/build.gradle', 'pubspec.lock') }}
restore-keys: |
${{ runner.os }}-gradle-
- run: flutter pub get
- run: flutter build apk --release --no-pub
ios:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
channel: "stable"
cache: true
- run: flutter pub get
- run: flutter build ios --release --no-codesign --no-pub
linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
channel: "stable"
cache: true
- name: Install Linux build deps
run: sudo apt-get update && sudo apt-get install -y clang cmake ninja-build pkg-config libgtk-3-dev
- run: flutter pub get
- run: flutter build linux --release --no-pub
macos:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
channel: "stable"
cache: true
- run: flutter pub get
- run: flutter build macos --release --no-pub
web:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
channel: "stable"
cache: true
- run: flutter pub get
- run: flutter build web --release --no-pub

23
.github/workflows/flutter_analyze.yml vendored Normal file
View file

@ -0,0 +1,23 @@
name: Flutter Analyze
on:
pull_request:
push:
jobs:
analyze:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
channel: stable
- name: Install dependencies
run: flutter pub get
- name: Analyze
run: flutter analyze --fatal-infos --fatal-warnings

1
.gitignore vendored
View file

@ -70,6 +70,7 @@ secrets.dart
**/android/local.properties
**/android/.externalNativeBuild/
*.jks
key.properties
keystore.properties
# Generated files

View file

@ -1,3 +1,5 @@
import java.util.Properties
plugins {
id("com.android.application")
id("kotlin-android")
@ -5,6 +7,12 @@ plugins {
id("dev.flutter.flutter-gradle-plugin")
}
val keystoreProperties = Properties()
val keystorePropertiesFile = rootProject.file("key.properties")
if (keystorePropertiesFile.exists()) {
keystorePropertiesFile.inputStream().use { keystoreProperties.load(it) }
}
android {
namespace = "com.meshcore.meshcore_open"
compileSdk = flutter.compileSdkVersion
@ -40,11 +48,25 @@ android {
// }
}
signingConfigs {
create("release") {
val storeFilePath = keystoreProperties["storeFile"] as String?
if (storeFilePath != null) {
storeFile = file(storeFilePath)
storePassword = keystoreProperties["storePassword"] as String?
keyAlias = keystoreProperties["keyAlias"] as String?
keyPassword = keystoreProperties["keyPassword"] as String?
}
}
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.getByName("debug")
signingConfig = if (keystorePropertiesFile.exists()) {
signingConfigs.getByName("release")
} else {
signingConfigs.getByName("debug")
}
}
}

View file

@ -1766,7 +1766,7 @@ class MeshCoreConnector extends ChangeNotifier {
_batteryMillivolts = readUint16LE(frame, 1);
final volts = (_batteryMillivolts! / 1000.0).toStringAsFixed(2);
_appDebugLogService?.info(
'Pulled battery: $volts V (${_batteryMillivolts} mV)',
'Pulled battery: $volts V ($_batteryMillivolts mV)',
tag: 'Battery',
);
notifyListeners();
@ -2272,7 +2272,6 @@ class MeshCoreConnector extends ChangeNotifier {
// [6-9] = estimated_timeout_ms (uint32)
if (frame.length >= 10) {
final isFlood = frame[1] != 0;
final ackHash = Uint8List.fromList(frame.sublist(2, 6));
final timeoutMs = readUint32LE(frame, 6);
@ -2618,7 +2617,7 @@ class MeshCoreConnector extends ChangeNotifier {
final keyLen = psk.length < 16 ? psk.length : 16;
key16.setRange(0, keyLen, psk);
final cipher = ECBBlockCipher(AESFastEngine());
final cipher = ECBBlockCipher(AESEngine());
cipher.init(false, KeyParameter(key16));
final out = Uint8List(cipherText.length);
for (var i = 0; i < cipherText.length; i += 16) {
@ -2992,7 +2991,6 @@ const int _phVerMask = 0x03;
const int _routeTransportFlood = 0x00;
const int _routeFlood = 0x01;
const int _routeDirect = 0x02;
const int _routeTransportDirect = 0x03;
const int _payloadTypeGroupText = 0x05;

View file

@ -821,6 +821,8 @@
}
}
},
"login_failedMessage": "Входът не беше успешен. Или паролата е грешна, или повторителят е недостъпен.",
"common_reload": "Презареди",
"common_clear": "Изчисти",
"path_currentPath": "Текущ път: {path}",
@ -1349,5 +1351,17 @@
"neighbors_RequestTimedOut": "Съседите поискат изтичане на време.",
"neighbors_errorLoading": "Грешка при зареждане на съседи: {error}",
"neighbors_repeatersNeighbours": "Повторители Съседи",
"neighbors_noData": "Няма налични данни за съседи."
"neighbors_noData": "Няма налични данни за съседи.",
"channels_createPrivateChannel": "Създай Частен Канал",
"channels_joinPrivateChannel": "Присъедини се към Частен Канал",
"channels_createPrivateChannelDesc": "Защитено с таен ключ.",
"channels_joinPrivateChannelDesc": "Ръчно въведете таен ключ.",
"channels_joinPublicChannel": "Присъединете се към Публичния канал",
"channels_joinPublicChannelDesc": "Всеки може да се присъедини към този канал.",
"channels_joinHashtagChannel": "Присъедини се към Хаштаг Канал",
"channels_joinHashtagChannelDesc": "Всеки може да се присъедини към хаштаговите канали.",
"channels_scanQrCode": "Сканирайте QR код",
"channels_scanQrCodeComingSoon": "Ще излезе скоро",
"channels_enterHashtag": "Въведете хаштаг",
"channels_hashtagHint": "напр. #отбор"
}

View file

@ -69,7 +69,7 @@
},
"scanner_stop": "Stopp",
"scanner_scan": "Scannen",
"device_quickSwitch": "Schneller Umschalten",
"device_quickSwitch": "Schnelles Umschalten",
"device_meshcore": "MeshCore",
"settings_title": "Einstellungen",
"settings_deviceInfo": "Geräteinformationen",
@ -78,7 +78,7 @@
"settings_nodeSettings": "Knoten-Einstellungen",
"settings_nodeName": "Knotenname",
"settings_nodeNameNotSet": "Nicht festgelegt",
"settings_nodeNameHint": "Gib den Knotenamen ein",
"settings_nodeNameHint": "Gebe den Knotenamen ein",
"settings_nodeNameUpdated": "Name aktualisiert",
"settings_radioSettings": "Funk Einstellungen",
"settings_radioSettingsSubtitle": "Frequenz, Leistung, Verbreitungsfaktor",
@ -90,17 +90,17 @@
"settings_locationInvalid": "Ungültige Breiten- oder Längengrade.",
"settings_latitude": "Breitengrad",
"settings_longitude": "Längengrad",
"settings_privacyMode": "Privatschutzzustand",
"settings_privacyModeSubtitle": "Verstecken Sie Name/Ort in Anzeigen",
"settings_privacyModeToggle": "Aktivieren Sie den Datenschutzzustand, um Ihren Namen und Ihre Standortdaten in Anzeigen zu verbergen.",
"settings_privacyModeEnabled": "Privatschutzzustand aktiviert",
"settings_privacyMode": "Privatsphäreeinstellung",
"settings_privacyModeSubtitle": "Verstecken Sie Name/Ort in Ankündigungen",
"settings_privacyModeToggle": "Aktivieren Sie die Privatsphäreeinstellung, um Ihren Namen und Ihre Standortdaten in Ankündigungen zu verbergen.",
"settings_privacyModeEnabled": "Datenschutzmodus aktiviert",
"settings_privacyModeDisabled": "Datenschutzmodus deaktiviert",
"settings_actions": "Aktionen",
"settings_sendAdvertisement": "Senden Sie Anzeige",
"settings_sendAdvertisementSubtitle": "Sendungsstatus jetzt",
"settings_advertisementSent": "Anzeige gesendet",
"settings_syncTime": "Synchronisierungszeit",
"settings_syncTimeSubtitle": "Stelle die Gerätewielfalt auf die Uhrzeit des Telefons ein",
"settings_sendAdvertisement": "Sende eine Ankündigung",
"settings_sendAdvertisementSubtitle": "Sende Ankündigung",
"settings_advertisementSent": "Ankündigung gesendet",
"settings_syncTime": "Zeitsynchronisierung",
"settings_syncTimeSubtitle": "Stelle die Gerätezeit auf die Uhrzeit des Telefons ein",
"settings_timeSynchronized": "Zeit synchronisiert",
"settings_refreshContacts": "Kontakte aktualisieren",
"settings_refreshContactsSubtitle": "Kontakte-Liste vom Gerät neu laden",
@ -128,8 +128,8 @@
"settings_infoStatus": "Status",
"settings_infoBattery": "Akku",
"settings_infoPublicKey": "Öffentlicher Schlüssel",
"settings_infoContactsCount": "Kontakte Anzahl",
"settings_infoChannelCount": "Kanalanzahl",
"settings_infoContactsCount": "Anzahl Kontakte",
"settings_infoChannelCount": "Anzahl Kanäle",
"settings_presets": "Voreinstellungen",
"settings_preset915Mhz": "915 MHz",
"settings_preset868Mhz": "868 MHz",
@ -139,11 +139,11 @@
"settings_frequencyInvalid": "Ungültige Frequenz (300-2500 MHz)",
"settings_bandwidth": "Bandbreite",
"settings_spreadingFactor": "Verteilungsfaktor",
"settings_codingRate": "Programmierpauschale",
"settings_codingRate": "Kodierungsrate",
"settings_txPower": "TX-Leistung (dBm)",
"settings_txPowerHelper": "0 - 22",
"settings_txPowerInvalid": "Ungültige TX-Leistung (0-22 dBm)",
"settings_longRange": "Langreich",
"settings_longRange": "Grosse Reichweite",
"settings_fastSpeed": "Schnelle Geschwindigkeit",
"settings_error": "Fehler: {message}",
"@settings_error": {
@ -157,7 +157,7 @@
"appSettings_appearance": "Aussehen",
"appSettings_theme": "Theme",
"appSettings_themeSystem": "Systemstandard",
"appSettings_themeLight": "Helligkeit",
"appSettings_themeLight": "Hell",
"appSettings_themeDark": "Dunkel",
"appSettings_language": "Sprache",
"appSettings_languageSystem": "Systemstandard",
@ -176,19 +176,19 @@
"appSettings_languageBg": "Български",
"appSettings_notifications": "Benachrichtigungen",
"appSettings_enableNotifications": "Benachrichtigungen aktivieren",
"appSettings_enableNotificationsSubtitle": "Erhalte Benachrichtigungen für Nachrichten und Anzeigen",
"appSettings_enableNotificationsSubtitle": "Erhalte Benachrichtigungen für Nachrichten und Ankündigungen",
"appSettings_notificationPermissionDenied": "Erlaubnis zur Benachrichtigung verweigert",
"appSettings_notificationsEnabled": "Benachrichtigungen aktiviert",
"appSettings_notificationsDisabled": "Benachrichtigungen deaktiviert",
"appSettings_messageNotifications": "Nachrichtenbenachrichtigungen",
"appSettings_messageNotificationsSubtitle": "Zeige Benachrichtigung beim Empfang neuer Nachrichten",
"appSettings_channelMessageNotifications": "Kanal-Nachrichten-Benachrichtigungen",
"appSettings_messageNotifications": "Direktnachrichten Benachrichtigungen",
"appSettings_messageNotificationsSubtitle": "Zeige Benachrichtigung beim Empfang neuer Direktnachrichten",
"appSettings_channelMessageNotifications": "Kanalnachrichten Benachrichtigungen",
"appSettings_channelMessageNotificationsSubtitle": "Zeige Benachrichtigung beim Empfangen von Kanalnachrichten",
"appSettings_advertisementNotifications": "Werbeanzeigenbenachrichtigungen",
"appSettings_advertisementNotifications": "Ankündigungsbenachrichtigungen",
"appSettings_advertisementNotificationsSubtitle": "Zeige Benachrichtigung, wenn neue Knoten entdeckt werden.",
"appSettings_messaging": "Nachrichten",
"appSettings_clearPathOnMaxRetry": "Klares Pfad bei Max Wiederholungsversuch",
"appSettings_clearPathOnMaxRetrySubtitle": "Zurücksetzen des Kontaktpfads nach 5 fehlgeschlagenen Sendeverboten",
"appSettings_clearPathOnMaxRetry": "Lösche Pfade bei Max Wiederholungsversuchen",
"appSettings_clearPathOnMaxRetrySubtitle": "Zurücksetzen der Kontaktpfade nach 5 fehlgeschlagenen Sendeabbrüchen",
"appSettings_pathsWillBeCleared": "Die Pfade werden nach 5 fehlgeschlagenen Versuchen gelöscht.",
"appSettings_pathsWillNotBeCleared": "Die Pfade werden nicht automatisch gelöscht.",
"appSettings_autoRouteRotation": "Automatische Routenrotation",
@ -226,10 +226,10 @@
}
}
},
"appSettings_mapTimeFilter": "Kartent Zeitfilter",
"appSettings_mapTimeFilter": "Karten Zeitfilter",
"appSettings_showNodesDiscoveredWithin": "Zeige Knoten, die innerhalb von:",
"appSettings_allTime": "Alle Zeit",
"appSettings_lastHour": "Letzter Stunde",
"appSettings_allTime": "Ganzer Zeitverlauf",
"appSettings_lastHour": "Letzte Stunde",
"appSettings_last6Hours": "Letzte 6 Stunden",
"appSettings_last24Hours": "Letzte 24 Stunden",
"appSettings_lastWeek": "Letzte Woche",
@ -252,13 +252,13 @@
"appSettings_appDebugLoggingEnabled": "App-Debug-Protokollierung aktiviert",
"appSettings_appDebugLoggingDisabled": "App-Debug-Protokollierung deaktiviert",
"contacts_title": "Kontakte",
"contacts_noContacts": "No Contacts noch",
"contacts_contactsWillAppear": "Kontakte werden angezeigt, wenn Geräte Werbung machen.",
"contacts_noContacts": "Noch keine Kontakte vorhanden.",
"contacts_contactsWillAppear": "Kontakte werden angezeigt, wenn Geräte eine Ankündigung machen.",
"contacts_searchContacts": "Suche Kontakte...",
"contacts_noUnreadContacts": "Keine ungeklärten Kontakte",
"contacts_noUnreadContacts": "Keine ungesehene Kontakte",
"contacts_noContactsFound": "Keine Kontakte oder Gruppen gefunden.",
"contacts_deleteContact": "Löschen Sie Kontakt",
"contacts_removeConfirm": "Entfernen {contactName} aus den Kontakten?",
"contacts_deleteContact": "Lösche den Kontakt",
"contacts_removeConfirm": "{contactName} aus den Kontakten entfernen?",
"@contacts_removeConfirm": {
"placeholders": {
"contactName": {
@ -266,12 +266,12 @@
}
}
},
"contacts_manageRepeater": "Wiederholung verwalten",
"contacts_manageRepeater": "Wiederholungen verwalten",
"contacts_roomLogin": "Raum-Login",
"contacts_openChat": "Öffnen Sie Chat",
"contacts_editGroup": "Gruppen bearbeiten",
"contacts_openChat": "Öffne Chat",
"contacts_editGroup": "Gruppe bearbeiten",
"contacts_deleteGroup": "Löschen Gruppe",
"contacts_deleteGroupConfirm": "Löschen Sie \"{groupName}\"?",
"contacts_deleteGroupConfirm": "Löschen von \"{groupName}\"?",
"@contacts_deleteGroupConfirm": {
"placeholders": {
"groupName": {
@ -293,8 +293,8 @@
"contacts_filterContacts": "Filtert Kontakte...",
"contacts_noContactsMatchFilter": "Keine Kontakte passen zu Ihrem Filter",
"contacts_noMembers": "Keine Mitglieder",
"contacts_lastSeenNow": "Letztes Ansehen jetzt",
"contacts_lastSeenMinsAgo": "Letzte Sichtung {minutes} Minuten her.",
"contacts_lastSeenNow": "gerade gesehen",
"contacts_lastSeenMinsAgo": "Letzte Sichtung vor {minutes} Minuten.",
"@contacts_lastSeenMinsAgo": {
"placeholders": {
"minutes": {
@ -303,7 +303,7 @@
}
},
"contacts_lastSeenHourAgo": "Letzte Sichtung vor 1 Stunde.",
"contacts_lastSeenHoursAgo": "Letzte Aktivität vor {hours} Stunden.",
"contacts_lastSeenHoursAgo": "Letzte Sichtung vor {hours} Stunden.",
"@contacts_lastSeenHoursAgo": {
"placeholders": {
"hours": {
@ -339,8 +339,8 @@
"channels_publicChannel": "Öffentlicher Kanal",
"channels_privateChannel": "Privater Kanal",
"channels_editChannel": "Kanal bearbeiten",
"channels_deleteChannel": "Löschen Sie Kanal",
"channels_deleteChannelConfirm": "Löschen \"{name}\"? Dies kann nicht rückgängig gemacht werden.",
"channels_deleteChannel": "Lösche den Kanal",
"channels_deleteChannelConfirm": "Löschen von \"{name}\"? Dies kann nicht rückgängig gemacht werden.",
"@channels_deleteChannelConfirm": {
"placeholders": {
"name": {
@ -373,7 +373,7 @@
}
}
},
"channels_editChannelTitle": "Bearbeiteten Kanal {index}",
"channels_editChannelTitle": "Bearbeiteter Kanal {index}",
"@channels_editChannelTitle": {
"placeholders": {
"index": {
@ -392,10 +392,10 @@
},
"channels_publicChannelAdded": "Öffentlicher Kanal hinzugefügt",
"channels_sortBy": "Sortiere nach",
"channels_sortManual": "Manuelle",
"channels_sortManual": "Manuell",
"channels_sortAZ": "A bis Z",
"channels_sortLatestMessages": "Letzte Nachrichten",
"channels_sortUnread": "Unlescht",
"channels_sortUnread": "Ungelesen",
"chat_noMessages": "Noch keine Nachrichten.",
"chat_sendMessageToStart": "Eine Nachricht senden, um anzufangen.",
"chat_originalMessageNotFound": "Originalmeldung nicht gefunden",
@ -407,7 +407,7 @@
}
}
},
"chat_replyTo": "Antworten Sie {name}",
"chat_replyTo": "Antwort an {name}",
"@chat_replyTo": {
"placeholders": {
"name": {
@ -436,7 +436,7 @@
"chat_messageCopied": "Nachricht kopiert",
"chat_messageDeleted": "Nachricht gelöscht",
"chat_retryingMessage": "Versuche es erneut.",
"chat_retryCount": "Versuchen {current}/{max}",
"chat_retryCount": "Versuche {current}/{max}",
"@chat_retryCount": {
"placeholders": {
"current": {
@ -457,22 +457,22 @@
"emojiCategoryObjects": "Objekte",
"gifPicker_title": "Wähle ein GIF",
"gifPicker_searchHint": "Suche nach GIFs...",
"gifPicker_poweredBy": "Angetrieben von GIPHY",
"gifPicker_poweredBy": "Bereitgestellt von GIPHY",
"gifPicker_noGifsFound": "Keine GIFs gefunden",
"gifPicker_failedLoad": "GIF-Dateien konnten nicht geladen werden.",
"gifPicker_failedLoad": "GIF-Datei konnten nicht geladen werden.",
"gifPicker_failedSearch": "Suche nach GIFs fehlgeschlagen",
"gifPicker_noInternet": "Keine Internetverbindung",
"debugLog_appTitle": "App-Debug-Protokoll",
"debugLog_bleTitle": "BLE-Debug-Protokoll",
"debugLog_copyLog": "Kopieren Sie Protokoll",
"debugLog_clearLog": "Log löschen",
"debugLog_copyLog": "Kopieren des Protokolls",
"debugLog_clearLog": "Protokoll löschen",
"debugLog_copied": "Debug-Protokoll kopiert",
"debugLog_bleCopied": "BLE-Protokoll kopiert",
"debugLog_noEntries": "No Debug-Protokolle noch verfügbar",
"debugLog_enableInSettings": "Aktivieren Sie das App-Debug-Logging in den Einstellungen",
"debugLog_frames": "Rahmen",
"debugLog_rawLogRx": "Roh-Log-RX",
"debugLog_noBleActivity": "No BLE-Aktivität bisher",
"debugLog_noBleActivity": "Bisher keine BLE-Aktivität",
"debugFrame_length": "Rahmenlänge: {count} Bytes",
"@debugFrame_length": {
"placeholders": {
@ -539,12 +539,12 @@
"chat_pathManagement": "Pfadverwaltung",
"chat_routingMode": "Routenmodus",
"chat_autoUseSavedPath": "Automatisch (gespeicherten Pfad verwenden)",
"chat_forceFloodMode": "Zwangsgelände-Modus erzwingen",
"chat_forceFloodMode": "Flut-Modus erzwingen",
"chat_recentAckPaths": "Aktuelle ACK-Pfade (tasten, um zu verwenden):",
"chat_pathHistoryFull": "Die Pfadhistorie ist voll. Entferne Einträge, um neue hinzuzufügen.",
"chat_hopSingular": "Springe",
"chat_hopPlural": "Hops",
"chat_hopsCount": "{count} {count, plural, =1{Hop} other{Hops}}",
"chat_hopSingular": "Sprung",
"chat_hopPlural": "Sprünge",
"chat_hopsCount": "{count} {count, plural, =1{Sprung} other{Sprünge}}",
"@chat_hopsCount": {
"placeholders": {
"count": {
@ -552,17 +552,17 @@
}
}
},
"chat_successes": "Erfolgreiche",
"chat_successes": "Erfolgreich",
"chat_removePath": "Pfad entfernen",
"chat_noPathHistoryYet": "Noe eine Pfadhistorie vorhanden.\nSende eine Nachricht, um Pfade zu entdecken.",
"chat_noPathHistoryYet": "Keine eine Pfadhistorie vorhanden.\nSende eine Nachricht, um Pfade zu entdecken.",
"chat_pathActions": "Pfadaktionen:",
"chat_setCustomPath": "Lege benutzerdefinierten Pfad fest",
"chat_setCustomPathSubtitle": "Manuelle Routenpfad festlegen",
"chat_clearPath": "Klares Pfad",
"chat_clearPathSubtitle": "Zwinge bei nächster Sendung eine erneute Entdeckung durch.",
"chat_pathCleared": "Pfad freigelegt. Nächste Nachricht wird Route neu entdecken.",
"chat_setCustomPathSubtitle": "Manuellen Routenpfad festlegen",
"chat_clearPath": "Pfad zurücksetzen",
"chat_clearPathSubtitle": "Setze Pfad zurück, erkenne neuen Pfad bei nächster Sendung.",
"chat_pathCleared": "Pfad zurückgesetzt. Nächste Nachricht wird Route neu entdecken.",
"chat_floodModeSubtitle": "Verwende den Routingschalter in der App-Leiste",
"chat_floodModeEnabled": "Flutmodus aktiviert. Über den Routing-Icon in der App-Leiste wieder aktivieren.",
"chat_floodModeEnabled": "Flutmodus aktiviert.",
"chat_fullPath": "Vollständiger Pfad",
"chat_pathDetailsNotAvailable": "Die Pfaddetails sind noch nicht verfügbar. Versuchen Sie, eine Nachricht zu senden, um zu aktualisieren.",
"chat_pathSetHops": "Pfad gesetzt: {hopCount} {hopCount, plural, =1{hop} other{hops}} - {status}",
@ -576,15 +576,15 @@
}
}
},
"chat_pathSavedLocally": "Gespeichert lokal. Mit Verbinden zum Synchronisieren.",
"chat_pathSavedLocally": "Lokal Gespeichert. Bitte Verbinden zum Synchronisieren.",
"chat_pathDeviceConfirmed": "Gerät bestätigt.",
"chat_pathDeviceNotConfirmed": "Gerät noch nicht bestätigt.",
"chat_type": "Gib ein",
"chat_type": "Gebe ein",
"chat_path": "Pfad",
"chat_publicKey": "Öffentlicher Schlüssel",
"chat_compressOutgoingMessages": "Komprimieren ausgehende Nachrichten",
"chat_floodForced": "Überschwemmung (erzwungen)",
"chat_directForced": "Direkt (gezwungen)",
"chat_compressOutgoingMessages": "Komprimieren ausgehender Nachrichten",
"chat_floodForced": "Geflutet (erzwungen)",
"chat_directForced": "Direkt (erzwungen)",
"chat_hopsForced": "{count} Sprünge (erzwungen)",
"@chat_hopsForced": {
"placeholders": {
@ -593,10 +593,10 @@
}
}
},
"chat_floodAuto": "Überschwemmung (automatisch)",
"chat_floodAuto": "Geflutet (automatisch)",
"chat_direct": "Direkt",
"chat_poiShared": "Gemeinsamer POI",
"chat_unread": "Unlescht: {count}",
"chat_poiShared": "Geteilter POI",
"chat_unread": "Ungelesen: {count}",
"@chat_unread": {
"placeholders": {
"count": {
@ -604,9 +604,9 @@
}
}
},
"map_title": "Knotenkarte",
"map_title": "Karte",
"map_noNodesWithLocation": "Keine Knoten mit Standortdaten",
"map_nodesNeedGps": "Knoten müssen ihre GPS-Koordinaten\nteilen,\num auf der Karte\nerscheinen.",
"map_nodesNeedGps": "Knoten müssen ihre GPS-Koordinaten teilen,\num auf der Karte zu erscheinen.",
"map_nodesCount": "Knoten: {count}",
"@map_nodesCount": {
"placeholders": {
@ -623,24 +623,24 @@
}
}
},
"map_chat": "Chat",
"map_repeater": "Wiederholung",
"map_chat": "Benutzer",
"map_repeater": "Repeater",
"map_room": "Raum",
"map_sensor": "Sensor",
"map_pinDm": "Sperren (DM)",
"map_pinPrivate": "Privat-Pin",
"map_pinPublic": "Öffentliche Taste (PIN)",
"map_pinDm": "Pin (Kontakt)",
"map_pinPrivate": "Pin (Channel)",
"map_pinPublic": "Pin (Public)",
"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": "Flaggen",
"map_shareMarkerHere": "Teilen Sie hier das Marker.",
"map_pinLabel": "Kennzeichnungslabel",
"map_flags": "Flags",
"map_shareMarkerHere": "Teilen Sie den Marker hier.",
"map_pinLabel": "Pin Name",
"map_label": "Label",
"map_pointOfInterest": "Punkt von Interesse",
"map_sendToContact": "Senden an Kontakt",
"map_sendToChannel": "Senden Sie Kanal",
"map_sendToChannel": "Senden an Kanal",
"map_noChannelsAvailable": "Keine Kanäle verfügbar",
"map_publicLocationShare": "Öffentliche Standortfreigabe",
"map_publicLocationShareConfirm": "Sie werden kurz darauf einen Ort in {channelLabel} teilen. Dieser Kanal ist öffentlich und jeder mit dem PSK kann ihn sehen.",
@ -652,25 +652,25 @@
}
},
"map_connectToShareMarkers": "Verbinde ein Gerät, um Marker zu teilen",
"map_filterNodes": "Filter Knoten",
"map_filterNodes": "Knotenfilter",
"map_nodeTypes": "Knotentypen",
"map_chatNodes": "Chat-Knoten",
"map_repeaters": "Wiederholer",
"map_repeaters": "Repeater",
"map_otherNodes": "Andere Knoten",
"map_keyPrefix": "Schlüsselpräfix",
"map_filterByKeyPrefix": "Filter nach Schlüsselpräfix",
"map_publicKeyPrefix": "Öffentlicher Schlüsselpräfix",
"map_publicKeyPrefix": "Schlüsselpräfix",
"map_markers": "Marker",
"map_showSharedMarkers": "Zeige gemeinsam genutzte Marker",
"map_lastSeenTime": "Letzte Sichtung",
"map_sharedPin": "Gemeinsames Passwort",
"map_joinRoom": "Beitreten Sie dem Raum",
"map_manageRepeater": "Wiederholung verwalten",
"map_manageRepeater": "Repeater verwalten",
"mapCache_title": "Offline-Karten-Cache",
"mapCache_selectAreaFirst": "Wählen Sie zuerst einen Bereich zum Zwischenspeichern aus.",
"mapCache_noTilesToDownload": "Keine Tiles für diese Region zum Herunterladen verfügbar.",
"mapCache_downloadTilesTitle": "Herunterladen von Tiles",
"mapCache_downloadTilesPrompt": "Laden {count} Tiles für den Offline-Bereich herunter?",
"mapCache_noTilesToDownload": "Keine Kacheln für diese Region zum Herunterladen verfügbar.",
"mapCache_downloadTilesTitle": "Herunterladen von Kacheln",
"mapCache_downloadTilesPrompt": "Laden {count} Kacheln für den Offline-Bereich herunter?",
"@mapCache_downloadTilesPrompt": {
"placeholders": {
"count": {
@ -679,7 +679,7 @@
}
},
"mapCache_downloadAction": "Herunterladen",
"mapCache_cachedTiles": "Zwischengespeicherte {count} Fliesen",
"mapCache_cachedTiles": "Zwischengespeicherte {count} Kacheln",
"@mapCache_cachedTiles": {
"placeholders": {
"count": {
@ -687,7 +687,7 @@
}
}
},
"mapCache_cachedTilesWithFailed": "Zwischengespeicherte {downloaded} Tiles ({failed} fehlgeschlagen)",
"mapCache_cachedTilesWithFailed": "Zwischengespeicherte {downloaded} Kacheln ({failed} fehlgeschlagen)",
"@mapCache_cachedTilesWithFailed": {
"placeholders": {
"downloaded": {
@ -698,7 +698,7 @@
}
}
},
"mapCache_clearOfflineCacheTitle": "Leeren Offline-Cache",
"mapCache_clearOfflineCacheTitle": "Leere Offline-Cache",
"mapCache_clearOfflineCachePrompt": "Alle zwischengespeicherten Kartenraster entfernen?",
"mapCache_offlineCacheCleared": "Offline-Cache gelöscht",
"mapCache_noAreaSelected": "Kein Bereich ausgewählt",
@ -724,7 +724,7 @@
}
}
},
"mapCache_downloadTilesButton": "Herunterladen von Tiles",
"mapCache_downloadTilesButton": "Herunterladen von Kacheln",
"mapCache_clearCacheButton": "Cache leeren",
"mapCache_failedDownloads": "Fehlgeschlagene Downloads: {count}",
"@mapCache_failedDownloads": {
@ -785,10 +785,10 @@
"time_month": "Monat",
"time_months": "Monate",
"time_minutes": "Minuten",
"time_allTime": "Alle Zeit",
"time_allTime": "Ganzer Zeitraum",
"dialog_disconnect": "Trennen",
"dialog_disconnectConfirm": "Sind Sie sicher, dass Sie sich von diesem Gerät trennen möchten?",
"login_repeaterLogin": "Wiederholungseingang anmelden",
"login_repeaterLogin": "Beim Repeater anmelden",
"login_roomLogin": "Raum-Login",
"login_password": "Passwort",
"login_enterPassword": "Passwort eingeben",
@ -799,7 +799,7 @@
"login_routing": "Routen",
"login_routingMode": "Routenmodus",
"login_autoUseSavedPath": "Automatisch (gespeicherten Pfad verwenden)",
"login_forceFloodMode": "Zwangsgelände-Modus erzwingen",
"login_forceFloodMode": "Flut-Modus erzwingen",
"login_managePaths": "Pfadverwaltung",
"login_login": "Anmelden",
"login_attempt": "Versuche {current}/{max}",
@ -821,9 +821,11 @@
}
}
},
"login_failedMessage": "Anmeldung fehlgeschlagen. Entweder ist das Passwort falsch oder der Repeater ist nicht erreichbar.",
"common_reload": "Neu laden",
"common_clear": "Löschen",
"path_currentPath": "Aktiger Pfad: {path}",
"path_currentPath": "Aktiver Pfad: {path}",
"@path_currentPath": {
"placeholders": {
"path": {
@ -839,9 +841,9 @@
}
}
},
"path_enterCustomPath": "Gib Pfad an",
"path_enterCustomPath": "Gebe Pfad ein",
"path_currentPathLabel": "Aktueller Pfad",
"path_hexPrefixInstructions": "Gib für jeden Hopfen 2-stellige Hex-Präfixe ein, getrennt durch Kommas.",
"path_hexPrefixInstructions": "Gebe für jeden Hopfen 2-stellige Hex-Präfixe ein, getrennt durch Kommas.",
"path_hexPrefixExample": "Beispiel: A1,F2,3C (jeder Knoten verwendet den ersten Byte seines öffentlichen Schlüssels)",
"path_labelHexPrefixes": "Pfad (Hex-Präfixe)",
"path_helperMaxHops": "Max 64 Sprünge. Jede Präfixe ist 2 Hexadezimalzeichen (1 Byte)",
@ -858,7 +860,7 @@
},
"path_tooLong": "Pfad zu lang. Maximal 64 Hops erlaubt.",
"path_setPath": "Pfad festlegen",
"repeater_management": "Wiederholungselement-Verwaltung",
"repeater_management": "Repeater-Verwaltung",
"repeater_managementTools": "Verwaltungs-Tools",
"repeater_status": "Status",
"repeater_statusSubtitle": "Status, Statistiken und Nachbarn anzeigen",
@ -867,11 +869,11 @@
"repeater_cli": "CLI",
"repeater_cliSubtitle": "Sende Befehle an den Repeater",
"repeater_settings": "Einstellungen",
"repeater_settingsSubtitle": "Wiederholungsparameter konfigurieren",
"repeater_statusTitle": "Wiederholungszustand",
"repeater_settingsSubtitle": "Repeater-parameter konfigurieren",
"repeater_statusTitle": "Repeaterstatus",
"repeater_routingMode": "Routenmodus",
"repeater_autoUseSavedPath": "Automatisch (gespeicherten Pfad verwenden)",
"repeater_forceFloodMode": "Zwangsgelände-Modus erzwingen",
"repeater_forceFloodMode": "Flut-Modus erzwingen",
"repeater_pathManagement": "Pfadverwaltung",
"repeater_refresh": "Aktualisieren",
"repeater_statusRequestTimeout": "Statusanfrage zeitweise fehlgeschlagen.",
@ -963,9 +965,9 @@
}
}
},
"repeater_settingsTitle": "Wiederholungseinstellungen",
"repeater_settingsTitle": "Repeater Einstellungen",
"repeater_basicSettings": "Grundlegende Einstellungen",
"repeater_repeaterName": "Wiederholungseintrag",
"repeater_repeaterName": "Repeater Name",
"repeater_repeaterNameHelper": "Anzeigename für diesen Repeater",
"repeater_adminPassword": "Admin-Passwort",
"repeater_adminPasswordHelper": "Vollzugriffspasswort",
@ -978,7 +980,7 @@
"repeater_txPowerHelper": "1-30 dBm",
"repeater_bandwidth": "Bandbreite",
"repeater_spreadingFactor": "Verteilungsfaktor",
"repeater_codingRate": "Programmierpauschale",
"repeater_codingRate": "Kodierungsrate",
"repeater_locationSettings": "Standort Einstellungen",
"repeater_latitude": "Breitengrad",
"repeater_latitudeHelper": "Dezimalgrad (z.B. 37,7749)",
@ -989,10 +991,10 @@
"repeater_packetForwardingSubtitle": "Aktivieren Sie den Repeater, um Pakete weiterzuleiten.",
"repeater_guestAccess": "Gastzugriff",
"repeater_guestAccessSubtitle": "Gast-Zugriff mit beschränkten Rechten zulassen",
"repeater_privacyMode": "Privatschutzzustand",
"repeater_privacyModeSubtitle": "Verstecken Sie Name/Ort in Anzeigen",
"repeater_advertisementSettings": "Werbe Einstellungen",
"repeater_localAdvertInterval": "Lokaler Werbeintervall",
"repeater_privacyMode": "Privatsphäreeinstellung",
"repeater_privacyModeSubtitle": "Verstecken Sie Name/Ort in Ankündigungen",
"repeater_advertisementSettings": "Ankündigungseinstellungen",
"repeater_localAdvertInterval": "Intervall der lokalen Ankündigungen",
"repeater_localAdvertIntervalMinutes": "{minutes} Minuten",
"@repeater_localAdvertIntervalMinutes": {
"placeholders": {
@ -1001,7 +1003,7 @@
}
}
},
"repeater_floodAdvertInterval": "Überschwemmungsanzeige-Intervall",
"repeater_floodAdvertInterval": "Intervall der gefluteten Ankündigungen",
"repeater_floodAdvertIntervalHours": "{hours} Stunden",
"@repeater_floodAdvertIntervalHours": {
"placeholders": {
@ -1010,7 +1012,7 @@
}
}
},
"repeater_encryptedAdvertInterval": "Verschlüsselte Werbeintervall",
"repeater_encryptedAdvertInterval": "Intervall der verschlüsselten Ankündigung",
"repeater_dangerZone": "Gefahrenzone",
"repeater_rebootRepeater": "Neustart Repeater",
"repeater_rebootRepeaterSubtitle": "Wiederholen Sie das Repeater-Gerät.",
@ -1050,12 +1052,12 @@
},
"repeater_refreshBasicSettings": "Grundlegende Einstellungen aktualisieren",
"repeater_refreshRadioSettings": "Radio-Einstellungen aktualisieren",
"repeater_refreshTxPower": "Batterie-Strom 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 Werbe Einstellungen",
"repeater_refreshAdvertisementSettings": "Aktualisieren Sie die Ankündigungseinstellungen",
"repeater_refreshed": "{label} wurde aktualisiert",
"@repeater_refreshed": {
"placeholders": {
@ -1072,10 +1074,10 @@
}
}
},
"repeater_cliTitle": "Wiederholung CLI",
"repeater_cliTitle": "Repeater CLI",
"repeater_debugNextCommand": "Fehlersuche Nächster Befehl",
"repeater_commandHelp": "Hilfe",
"repeater_clearHistory": "Löschung der Historie",
"repeater_clearHistory": "Löschen der Historie",
"repeater_noCommandsSent": "Noch keine Befehle gesendet.",
"repeater_typeCommandOrUseQuick": "Geben Sie einen Befehl unten ein oder verwenden Sie Schnellbefehle",
"repeater_enterCommandHint": "Geben Sie den Befehl ein...",
@ -1096,37 +1098,37 @@
"repeater_cliQuickGetTx": "Erhalte TX",
"repeater_cliQuickNeighbors": "Nachbarn",
"repeater_cliQuickVersion": "Version",
"repeater_cliQuickAdvertise": "Werben",
"repeater_cliQuickAdvertise": "Ankündigungen",
"repeater_cliQuickClock": "Uhr",
"repeater_cliHelpAdvert": "Sendet ein Werbepaket",
"repeater_cliHelpAdvert": "Sendet eine Ankündigung",
"repeater_cliHelpReboot": "Startet das Gerät neu. (Beachten Sie, dass es möglicherweise zu einer 'Timeout'-Situation kommt, was normal ist.)",
"repeater_cliHelpClock": "Zeigt die aktuelle Uhrzeit pro Gerät an.",
"repeater_cliHelpPassword": "Legt ein neues Administrator-Passwort für das Gerät fest.",
"repeater_cliHelpVersion": "Zeigt die Geräteversion und das Datum des Firmware-Builds an.",
"repeater_cliHelpClearStats": "Setzt verschiedene Statistikkalkulate auf Null zurück.",
"repeater_cliHelpClearStats": "Setzt verschiedene Statistikberechnungen auf Null zurück.",
"repeater_cliHelpSetAf": "Legt den Luftzeitfaktor fest.",
"repeater_cliHelpSetTx": "Legt die LoRa-Übertragungspower in dBm (bezogen auf 1 Watt) fest. (Neustart erforderlich, um die Änderungen anzuwenden)",
"repeater_cliHelpSetRepeat": "Aktiviert oder deaktiviert die Repeater-Rolle für diesen Knoten.",
"repeater_cliHelpSetAllowReadOnly": "(Raumspeicher) Wenn 'an', dann wird die Anmeldung mit einem leeren Passwort erlaubt sein, aber kann nicht in den Raum geschickt werden. (nur lesen möglich).",
"repeater_cliHelpSetAllowReadOnly": "(Raumspeicher) Wenn 'an', dann wird die Anmeldung mit einem leeren Passwort erlaubt sein, aber es kann nicht in den Raum gesendet werden. (nur lesen möglich).",
"repeater_cliHelpSetFloodMax": "Legt die maximale Anzahl an Hops für Pakete der eingehenden Flut (wenn >= max, wird das Paket nicht weitergeleitet)",
"repeater_cliHelpSetIntThresh": "Legt den Interferenzeniveau (in dB) fest. Der Standardwert ist 14. Auf 0 setzen, um die Erkennung von Kanalinterferenzen zu deaktivieren.",
"repeater_cliHelpSetAgcResetInterval": "Legt das Intervall für das Zurücksetzen des Auto Gain Controllers fest. Auf 0 setzen, um die Funktion zu deaktivieren.",
"repeater_cliHelpSetMultiAcks": "Aktiviert oder deaktiviert die Funktion 'Doppel-ACKs'.",
"repeater_cliHelpSetAdvertInterval": "Legt das Timer-Intervall in Minuten fest, um ein lokales (ohne-Weiterleitung) Werbe-Paket zu senden. Auf 0 setzen, um die Funktion zu deaktivieren.",
"repeater_cliHelpSetFloodAdvertInterval": "Legt das Timer-Intervall in Stunden für den Versand eines Flut-Werbungspakets fest. Auf 0 setzen, um es zu deaktivieren.",
"repeater_cliHelpSetAdvertInterval": "Legt das Timer-Intervall in Minuten fest, um ein lokales (ohne-Weiterleitung) Ankündigungspaket zu senden. Auf 0 setzen, um die Funktion zu deaktivieren.",
"repeater_cliHelpSetFloodAdvertInterval": "Legt das Timer-Intervall in Stunden für den Versand eines Flut-Ankündigungspacket fest. Auf 0 setzen, um es zu deaktivieren.",
"repeater_cliHelpSetGuestPassword": "Legt/aktualisiert das Gastpasswort fest. (für Repeater können Gast-Logins die \"Get Stats\"-Anfrage senden)",
"repeater_cliHelpSetName": "Legt den Anzeigenamen fest.",
"repeater_cliHelpSetLat": "Legt die Breitengrad-Angabe der Werbekarte fest. (dezimale Grad)",
"repeater_cliHelpSetLon": "Legt die Längengrade der Werbe-Map fest. (dezimale Grad)",
"repeater_cliHelpSetLat": "Legt die Breitengrad der Ankündigung fest. (dezimale Grad)",
"repeater_cliHelpSetLon": "Legt die Längengrade der Ankündigung fest. (dezimale Grad)",
"repeater_cliHelpSetRadio": "Legt komplett neue Radio-Parameter fest und speichert diese als Präferenzen. Benötigt einen \"Reboot\"-Befehl, um sie anzuwenden.",
"repeater_cliHelpSetRxDelay": "Sets (experimentell) als Basis (muss > 1 sein für den Effekt) zur Anwendung einer leichten Verzögerung bei empfangenen Paketen, basierend auf Signalstärke/Punktzahl. Auf 0 setzen, um die Funktion zu deaktivieren.",
"repeater_cliHelpSetTxDelay": "Legt einen Faktor fest, der mit der Zeit bei voller Zuluft für ein Flood-Mode-Paket und mit einem zufälligen Slot-System multipliziert wird, um dessen Weiterleitung zu verzögern (um Kollisionen zu vermeiden).",
"repeater_cliHelpSetDirectTxDelay": "Ähnlich wie txdelay, aber zum Anwenden einer zufälligen Verzögerung bei der Weiterleitung von Direktmodus-Paketen.",
"repeater_cliHelpSetBridgeEnabled": "Brücke aktivieren/deaktivieren.",
"repeater_cliHelpSetBridgeDelay": "Setze Verzögerung vor erneuter Übertragung von Paketen.",
"repeater_cliHelpSetBridgeSource": "Wählen Sie, ob die Brücke empfangene oder gesendete Pakete erneut übertragen soll.",
"repeater_cliHelpSetBridgeSource": "Wählen Sie, ob über die Brücke empfangene oder gesendete Pakete erneut übertragen soll.",
"repeater_cliHelpSetBridgeBaud": "Setze die serielle Link-Baudrate für RS232-Brücken.",
"repeater_cliHelpSetBridgeSecret": "Richte das Espnow-Brücken-Geheimnis ein.",
"repeater_cliHelpSetBridgeSecret": "Richte das Brückenpassword ein.",
"repeater_cliHelpSetAdcMultiplier": "Legt einen benutzerdefinierten Faktor zur Anpassung der gemeldeten Batteriewirkspannung fest (nur auf ausgewählten Boards unterstützt).",
"repeater_cliHelpTempRadio": "Legt vorübergehende Funkparameter für die angegebene Anzahl von Minuten fest und kehrt anschließend zu den ursprünglichen Funkparametern zurück (wird nicht in den Einstellungen gespeichert).",
"repeater_cliHelpSetPerm": "Ändert die ACL. Entfernt das passende Eintragen (durch Pubkey-Präfix), wenn \"permissions\" auf 0 steht. Fügt ein neues Eintragen hinzu, wenn die Pubkey-Hex-Länge vollständig ist und nicht bereits in der ACL vorhanden ist. Aktualisiert das Eintragen anhand des übereinstimmenden Pubkey-Präfix. Berechtigungsbits variieren je nach Firmware-Rolle, aber die unteren 2 Bits sind: 0 (Gast), 1 (Nur Lesen), 2 (Lesen/Schreiben), 3 (Admin)",
@ -1134,9 +1136,9 @@
"repeater_cliHelpLogStart": "Beginnt die Paketprotokollierung in das Dateisystem.",
"repeater_cliHelpLogStop": "Stoppt das Paketprotokollieren in das Dateisystem.",
"repeater_cliHelpLogErase": "Löscht die Paketprotokolle aus dem Dateisystem.",
"repeater_cliHelpNeighbors": "Zeigt eine Liste anderer Repeater-Knoten an, die über Zero-Hop-Werbung gehört wurden. Jede Zeile ist id-prefix-hex:timestamp:snr-times-4",
"repeater_cliHelpNeighbors": "Zeigt eine Liste anderer Repeater-Knoten an, die über Zero-Hop-Ankündigung gehört wurden. Jede Zeile ist id-prefix-hex:timestamp:snr-times-4",
"repeater_cliHelpNeighborRemove": "Entfernt das erste übereinstimmende Element (über Pubkey-Präfix (hex)) aus der Liste der Nachbarn.",
"repeater_cliHelpRegion": "(Serien nur) Listet alle definierten Regionen und aktuelle Hochwassermissungen auf.",
"repeater_cliHelpRegion": "Listet alle definierten Regionen auf.",
"repeater_cliHelpRegionLoad": "Hinweis: Dies ist ein spezieller Mehrbefehl-Aufruf. Jeder nachfolgende Befehl ist ein Regionsname (eingedruckt mit Leerzeichen zur Angabe der übergeordneten Hierarchie, mit mindestens einem Leerzeichen). Beendet durch das Senden einer Leerzeile/des Befehls.",
"repeater_cliHelpRegionGet": "Sucht die Region mit dem gegebenen Namenspräfix (oder \"\\\" für den globalen Scope) und antwortet mit \"-> region-name (parent-name) 'F'\".",
"repeater_cliHelpRegionPut": "Fügt eine Region-Definition mit dem angegebenen Namen hinzu oder aktualisiert diese.",
@ -1228,12 +1230,12 @@
"channelPath_title": "Paketpfad",
"channelPath_viewMap": "Karte anzeigen",
"channelPath_otherObservedPaths": "Sonstige beobachtete Pfade",
"channelPath_repeaterHops": "Wiederholungs-Sprünge",
"channelPath_repeaterHops": "Repeater-Sprünge",
"channelPath_noHopDetails": "Die Detailangaben für dieses Paket sind nicht verfügbar.",
"channelPath_messageDetails": "Nachrichtsdetails",
"channelPath_senderLabel": "Sender",
"channelPath_timeLabel": "Zeit",
"channelPath_repeatsLabel": "Wiederholung",
"channelPath_repeatsLabel": "Wiederholungen",
"channelPath_pathLabel": "Pfad {index}",
"channelPath_observedLabel": "Beobachtet",
"channelPath_observedPathTitle": "Beobachteter Pfad {index} • {hops}",
@ -1271,7 +1273,7 @@
}
},
"channelPath_unknownPath": "Unbekannt",
"channelPath_floodPath": "Überschwemmung",
"channelPath_floodPath": "Geflutet",
"channelPath_directPath": "Direkt",
"channelPath_observedZeroOf": "0 von {total} Sprüngen",
"@channelPath_observedZeroOf": {
@ -1327,15 +1329,16 @@
"listFilter_tooltip": "Filteren und sortieren",
"listFilter_sortBy": "Sortiere nach",
"listFilter_latestMessages": "Letzte Nachrichten",
"listFilter_heardRecently": "Hörte kürzlich",
"listFilter_heardRecently": "Kürzlich gehört",
"listFilter_az": "A-Z",
"listFilter_filters": "Filtere",
"listFilter_all": "Alle",
"listFilter_users": "Benutzer",
"listFilter_repeaters": "Wiederholer",
"listFilter_repeaters": "Repeater",
"listFilter_roomServers": "Raumserver",
"listFilter_unreadOnly": "Nur nicht gelesen",
"listFilter_newGroup": "Neue Gruppe",
"@neighbors_errorLoading": {
"placeholders": {
"error": {
@ -1349,5 +1352,18 @@
"neighbors_RequestTimedOut": "Nachbarn melden zeitweise Ausfall.",
"neighbors_errorLoading": "Fehler beim Laden der Nachbarn: {error}",
"neighbors_repeatersNeighbours": "Wiederholer Nachbarn",
"neighbors_noData": "Keine Nachbardaten verfügbar."
"neighbors_noData": "Keine Nachbardaten verfügbar.",
"channels_joinPrivateChannel": "Treten Sie einem privaten Kanal bei",
"channels_joinPrivateChannelDesc": "Manuelle Eingabe eines geheimen Schlüssels.",
"channels_createPrivateChannel": "Erstelle einen privaten Kanal",
"channels_createPrivateChannelDesc": "Verschlüsselt mit einem geheimen Schlüssel.",
"channels_joinPublicChannel": "Tritt dem öffentlichen Kanal bei",
"channels_joinPublicChannelDesc": "Jeder kann diesem Kanal beitreten.",
"channels_joinHashtagChannel": "Treten Sie einem Hashtag-Kanal bei",
"channels_joinHashtagChannelDesc": "Jeder kann sich bei Hashtag-Kanälen beteiligen.",
"channels_scanQrCode": "Scannen Sie einen QR-Code",
"channels_scanQrCodeComingSoon": "Bald verfügbar",
"channels_enterHashtag": "Gib Hashtag ein",
"channels_hashtagHint": "z.B. #team"
}

View file

@ -361,6 +361,18 @@
"channels_sortAZ": "A-Z",
"channels_sortLatestMessages": "Latest messages",
"channels_sortUnread": "Unread",
"channels_createPrivateChannel": "Create a Private Channel",
"channels_createPrivateChannelDesc": "Secured with a secret key.",
"channels_joinPrivateChannel": "Join a Private Channel",
"channels_joinPrivateChannelDesc": "Manually enter a secret key.",
"channels_joinPublicChannel": "Join the Public Channel",
"channels_joinPublicChannelDesc": "Anyone can join this channel.",
"channels_joinHashtagChannel": "Join a Hashtag Channel",
"channels_joinHashtagChannelDesc": "Anyone can join hashtag channels.",
"channels_scanQrCode": "Scan a QR Code",
"channels_scanQrCodeComingSoon": "Coming soon",
"channels_enterHashtag": "Enter hashtag",
"channels_hashtagHint": "e.g. #team",
"chat_noMessages": "No messages yet",
"chat_sendMessageToStart": "Send a message to get started",
@ -711,6 +723,8 @@
"error": {"type": "String"}
}
},
"login_failedMessage": "Login failed. Either the password is incorrect or the repeater is unreachable.",
"common_reload": "Reload",
"common_clear": "Clear",

View file

@ -821,6 +821,8 @@
}
}
},
"login_failedMessage": "Inicio fallido. La contraseña es incorrecta o el repetidor no está disponible.",
"common_reload": "Recargar",
"common_clear": "Borrar",
"path_currentPath": "Ruta actual: {path}",
@ -1336,6 +1338,7 @@
"listFilter_roomServers": "Servidores de la sala",
"listFilter_unreadOnly": "Solo sin leer",
"listFilter_newGroup": "Nuevo grupo",
"@neighbors_errorLoading": {
"placeholders": {
"error": {
@ -1349,5 +1352,18 @@
"neighbors_RequestTimedOut": "Los vecinos solicitan que se desconecte.",
"neighbors_errorLoading": "Error al cargar vecinos: {error}",
"neighbors_repeatersNeighbours": "Repetidores Vecinos",
"neighbors_noData": "No hay datos de vecinos disponibles."
"neighbors_noData": "No hay datos de vecinos disponibles.",
"channels_joinPrivateChannel": "Únete a un Canal Privado",
"channels_createPrivateChannel": "Crear un Canal Privado",
"channels_createPrivateChannelDesc": "Cifrado con una clave secreta.",
"channels_joinPrivateChannelDesc": "Introducir manualmente una clave secreta.",
"channels_joinPublicChannel": "Únete al Canal Público",
"channels_joinPublicChannelDesc": "Cualquiera puede unirse a este canal.",
"channels_joinHashtagChannel": "Únete a un Canal con Hashtag",
"channels_joinHashtagChannelDesc": "Cualquiera puede unirse a los canales de hashtag.",
"channels_scanQrCode": "Escanear un Código QR",
"channels_scanQrCodeComingSoon": "Próximamente",
"channels_enterHashtag": "Introducir hashtag",
"channels_hashtagHint": "ej. #equipo"
}

View file

@ -91,12 +91,12 @@
"settings_latitude": "Latitude",
"settings_longitude": "Longitude",
"settings_privacyMode": "Mode de confidentialité",
"settings_privacyModeSubtitle": "Cacher le nom/l'emplacement dans les publicités",
"settings_privacyModeToggle": "Activer le mode confidentialité pour masquer votre nom et votre localisation dans les publicités.",
"settings_privacyModeSubtitle": "Cacher le nom/l'emplacement dans les annonces",
"settings_privacyModeToggle": "Activer le mode confidentialité pour masquer votre nom et votre localisation dans les annonces.",
"settings_privacyModeEnabled": "Mode de confidentialité activé",
"settings_privacyModeDisabled": "Mode de confidentialité désactivé",
"settings_actions": "Actions",
"settings_sendAdvertisement": "Envoyer la publicité",
"settings_sendAdvertisement": "S'annoncer",
"settings_sendAdvertisementSubtitle": "Présence diffusée maintenant",
"settings_advertisementSent": "Annonce envoyée",
"settings_syncTime": "Temps de synchronisation",
@ -176,7 +176,7 @@
"appSettings_languageBg": "Български",
"appSettings_notifications": "Notifications",
"appSettings_enableNotifications": "Activer les Notifications",
"appSettings_enableNotificationsSubtitle": "Recevoir des notifications pour les messages et les publicités",
"appSettings_enableNotificationsSubtitle": "Recevoir des notifications pour les messages et les annonces",
"appSettings_notificationPermissionDenied": "Permission de notification refusée",
"appSettings_notificationsEnabled": "Notifications activées",
"appSettings_notificationsDisabled": "Notifications désactivées",
@ -184,7 +184,7 @@
"appSettings_messageNotificationsSubtitle": "Afficher une notification lors de la réception de nouveaux messages",
"appSettings_channelMessageNotifications": "Notifications des Messages de Canal",
"appSettings_channelMessageNotificationsSubtitle": "Afficher une notification lors de la réception des messages de canal",
"appSettings_advertisementNotifications": "Notifications publicitaires",
"appSettings_advertisementNotifications": "Notifications d'annonces",
"appSettings_advertisementNotificationsSubtitle": "Afficher une notification lors de la découverte de nouveaux nœuds",
"appSettings_messaging": "Messagerie",
"appSettings_clearPathOnMaxRetry": "Effacer le chemin sur Max Retry",
@ -192,7 +192,7 @@
"appSettings_pathsWillBeCleared": "Les chemins seront effacés après 5 tentatives infructueuses.",
"appSettings_pathsWillNotBeCleared": "Les chemins ne seront pas effacés automatiquement.",
"appSettings_autoRouteRotation": "Rotation de l'itinéraire automatique",
"appSettings_autoRouteRotationSubtitle": "Alterner entre les meilleurs chemins et le mode inondation",
"appSettings_autoRouteRotationSubtitle": "Alterner entre les meilleurs chemins et le mode d'envoi sur tout le réseau (flood)",
"appSettings_autoRouteRotationEnabled": "Rotation du routage automatique activée",
"appSettings_autoRouteRotationDisabled": "Rotation de l'itinéraire automatique désactivée",
"appSettings_battery": "Batterie",
@ -539,7 +539,7 @@
"chat_pathManagement": "Gestion des chemins",
"chat_routingMode": "Mode de routage",
"chat_autoUseSavedPath": "Auto (utiliser le chemin sauvegardé)",
"chat_forceFloodMode": "Mode Inondation Forcée",
"chat_forceFloodMode": "Mode tout le réseau forcé",
"chat_recentAckPaths": "Chemins ACK récents (touchez pour utiliser) :",
"chat_pathHistoryFull": "L'historique du chemin est plein. Supprimez les entrées pour en ajouter de nouvelles.",
"chat_hopSingular": "Sautez",
@ -562,7 +562,7 @@
"chat_clearPathSubtitle": "Forcer la redécouverte lors de la prochaine envoi",
"chat_pathCleared": "Le chemin est dégagé. Le prochain message redécouvrira le tracé.",
"chat_floodModeSubtitle": "Utiliser le commutateur de routage dans la barre d'application",
"chat_floodModeEnabled": "Le mode inondation est activé. Réactiver via l'icône de routage dans la barre d'outils.",
"chat_floodModeEnabled": "Le mode envoi à tout le réseau est activé. Changer via l'icône de routage dans la barre d'outils.",
"chat_fullPath": "Chemin complet",
"chat_pathDetailsNotAvailable": "Les détails du chemin ne sont pas encore disponibles. Essayez d'envoyer un message pour rafraîchir.",
"chat_pathSetHops": "Chemin défini : {hopCount} {hopCount, plural, =1{hop} other{hops}} - {status}",
@ -583,7 +583,7 @@
"chat_path": "Chemin",
"chat_publicKey": "Clé Publique",
"chat_compressOutgoingMessages": "Compresser les messages sortants",
"chat_floodForced": "Inondation (forcée)",
"chat_floodForced": "Tout le réseau (forcée)",
"chat_directForced": "Direct (forcé)",
"chat_hopsForced": "{count} sauts (forcés)",
"@chat_hopsForced": {
@ -593,7 +593,7 @@
}
}
},
"chat_floodAuto": "Inondation (auto)",
"chat_floodAuto": "Tout le réseau (auto)",
"chat_direct": "Afficher",
"chat_poiShared": "Point d'intérêt Partagé",
"chat_unread": "Non lu : {count}",
@ -799,7 +799,7 @@
"login_routing": "Redirection",
"login_routingMode": "Mode de routage",
"login_autoUseSavedPath": "Auto (utiliser le chemin sauvegardé)",
"login_forceFloodMode": "Mode Inondation Forcée",
"login_forceFloodMode": "Mode tout le réseau forcé",
"login_managePaths": "Gérer les chemins",
"login_login": "Connexion",
"login_attempt": "Essayer {current}/{max}",
@ -821,6 +821,8 @@
}
}
},
"login_failedMessage": "Connexion échouée. Soit le mot de passe est incorrect, soit le relais est injoignable.",
"common_reload": "Recharger",
"common_clear": "Effacer",
"path_currentPath": "Chemin actuel : {path}",
@ -871,7 +873,7 @@
"repeater_statusTitle": "État du répétiteur",
"repeater_routingMode": "Mode de routage",
"repeater_autoUseSavedPath": "Auto (utiliser le chemin sauvegardé)",
"repeater_forceFloodMode": "Mode de submersion forcée",
"repeater_forceFloodMode": "Mode tout le réseau forcé",
"repeater_pathManagement": "Gestion des chemins",
"repeater_refresh": "Rafraîchir",
"repeater_statusRequestTimeout": "Demande de statut délai dépassé.",
@ -916,7 +918,7 @@
}
}
},
"repeater_packetTxTotal": "Total : {total}, Inondation : {flood}, Direct : {direct}",
"repeater_packetTxTotal": "Total : {total}, Tout le réseau : {flood}, Direct : {direct}",
"@repeater_packetTxTotal": {
"placeholders": {
"total": {
@ -930,7 +932,7 @@
}
}
},
"repeater_packetRxTotal": "Total : {total}, Inondation : {flood}, Direct : {direct}",
"repeater_packetRxTotal": "Total : {total}, Tout le réseau : {flood}, Direct : {direct}",
"@repeater_packetRxTotal": {
"placeholders": {
"total": {
@ -944,7 +946,7 @@
}
}
},
"repeater_duplicatesFloodDirect": "Inondation : {flood}, Direct : {direct}",
"repeater_duplicatesFloodDirect": "Tout le réseau : {flood}, Direct : {direct}",
"@repeater_duplicatesFloodDirect": {
"placeholders": {
"flood": {
@ -990,9 +992,9 @@
"repeater_guestAccess": "Accès Invité",
"repeater_guestAccessSubtitle": "Autoriser l'accès invité en lecture seule",
"repeater_privacyMode": "Mode de confidentialité",
"repeater_privacyModeSubtitle": "Cacher le nom/l'emplacement dans les publicités",
"repeater_advertisementSettings": "Paramètres de Publicité",
"repeater_localAdvertInterval": "Intervalle Publicité Locale",
"repeater_privacyModeSubtitle": "Cacher le nom/l'emplacement dans les annonces",
"repeater_advertisementSettings": "Paramètres d'annonces",
"repeater_localAdvertInterval": "Intervalle des annonces Locale (0 saut)",
"repeater_localAdvertIntervalMinutes": "{minutes} minutes",
"@repeater_localAdvertIntervalMinutes": {
"placeholders": {
@ -1001,7 +1003,7 @@
}
}
},
"repeater_floodAdvertInterval": "Intervalle de Publicité Inondation",
"repeater_floodAdvertInterval": "Intervalle des annonces à tout le réseau (flood)",
"repeater_floodAdvertIntervalHours": "{hours} heures",
"@repeater_floodAdvertIntervalHours": {
"placeholders": {
@ -1010,7 +1012,7 @@
}
}
},
"repeater_encryptedAdvertInterval": "Intervalle publicitaire crypté",
"repeater_encryptedAdvertInterval": "Intervalle d'annonces cryptées",
"repeater_dangerZone": "Zone d'alerte",
"repeater_rebootRepeater": "Redémarrer Répéteur",
"repeater_rebootRepeaterSubtitle": "Réinitialiser l'appareil répétiteur",
@ -1055,7 +1057,7 @@
"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 de la Publicité",
"repeater_refreshAdvertisementSettings": "Rafraîchir les Paramètres des annonces",
"repeater_refreshed": "{label} rafraîchi",
"@repeater_refreshed": {
"placeholders": {
@ -1098,7 +1100,7 @@
"repeater_cliQuickVersion": "Version",
"repeater_cliQuickAdvertise": "Publier",
"repeater_cliQuickClock": "Horloge",
"repeater_cliHelpAdvert": "Envoie un paquet publicitaire",
"repeater_cliHelpAdvert": "Envoie un paquet d'annonce",
"repeater_cliHelpReboot": "Redémarre l'appareil. (Note, vous risquez d'obtenir 'Timeout' ce qui est normal)",
"repeater_cliHelpClock": "Affiche l'heure actuelle par l'horloge de chaque appareil.",
"repeater_cliHelpPassword": "Définit un nouveau mot de passe administrateur pour l'appareil.",
@ -1115,12 +1117,12 @@
"repeater_cliHelpSetAdvertInterval": "Définit l'intervalle du minuteur pour envoyer un paquet d'annonce local (sans relais). Définir sur 0 pour désactiver.",
"repeater_cliHelpSetFloodAdvertInterval": "Définit l'intervalle du minuteur en heures pour envoyer un paquet d'annonce massive. Définir sur 0 pour désactiver.",
"repeater_cliHelpSetGuestPassword": "Définit/met à jour le mot de passe de l'invité. (pour les répéteurs, les connexions d'invités peuvent envoyer la requête \"Get Stats\")",
"repeater_cliHelpSetName": "Définit le nom de la publicité.",
"repeater_cliHelpSetName": "Définit le nom de l'annonce.",
"repeater_cliHelpSetLat": "Définit la latitude de la carte des annonces. (degrés décimaux)",
"repeater_cliHelpSetLon": "Définit la longitude de la carte de l'annonce. (degrés décimaux)",
"repeater_cliHelpSetRadio": "Définit complètement de nouveaux paramètres de radio et les enregistre dans les préférences. Nécessite une commande \"redémarrage\" pour les appliquer.",
"repeater_cliHelpSetRxDelay": "Paramètres (expérimental) de base pour appliquer un léger délai aux paquets reçus, en fonction de la force du signal/score. Définir sur 0 pour désactiver.",
"repeater_cliHelpSetTxDelay": "Définit un facteur multiplié par le temps de fonctionnement en mode inondation pour un paquet et avec un système de slot aléatoire, afin de retarder son envoi (pour diminuer la probabilité de collisions).",
"repeater_cliHelpSetTxDelay": "Définit un facteur multiplié par le temps de fonctionnement en mode vers tout le réseau (flood) pour un paquet et avec un système de slot aléatoire, afin de retarder son envoi (pour diminuer la probabilité de collisions).",
"repeater_cliHelpSetDirectTxDelay": "Identique à txdelay, mais pour appliquer un délai aléatoire au transfert des paquets en mode direct.",
"repeater_cliHelpSetBridgeEnabled": "Activer/Désactiver le pont.",
"repeater_cliHelpSetBridgeDelay": "Définir le délai avant de renvoyer les paquets.",
@ -1134,9 +1136,9 @@
"repeater_cliHelpLogStart": "Démarre l'enregistrement des paquets dans le système de fichiers.",
"repeater_cliHelpLogStop": "Arrêter de journaliser les paquets vers le système de fichiers.",
"repeater_cliHelpLogErase": "Supprime les journaux de paquets du système de fichiers.",
"repeater_cliHelpNeighbors": "Affiche une liste d'autres nœuds répétiteurs entendus via des publicités sans relais. Chaque ligne est id-préfixe-hexadécimal:timestamp:snr-fois-4",
"repeater_cliHelpNeighbors": "Affiche une liste d'autres nœuds répétiteurs entendus via des annonces sans relais. Chaque ligne est id-préfixe-hexadécimal:timestamp:snr-fois-4",
"repeater_cliHelpNeighborRemove": "Supprime la première entrée correspondante (par préfixe de clé publique (hexadécimal)) de la liste des voisins.",
"repeater_cliHelpRegion": "(série uniquement) Liste toutes les régions définies et les autorisations de débordement actuelles.",
"repeater_cliHelpRegion": "(série uniquement) Liste toutes les régions définies et les autorisations actuelles d'annonces sur tout le réseau (flood).",
"repeater_cliHelpRegionLoad": "REMARQUE : il s'agit d'une invocation multi-commande spéciale. Chaque commande subséquente est un nom de région (indenté avec des espaces pour indiquer la hiérarchie parent, avec un minimum d'un espace). Terminé par l'envoi d'une ligne vide/commande.",
"repeater_cliHelpRegionGet": "Recherche la région avec le préfixe de nom donné (ou \"\" pour l'étendue globale). Répond avec \"-> nom-de-région (nom-parent) 'F'\"",
"repeater_cliHelpRegionPut": "Ajoute ou met à jour une définition de région avec le nom donné.",
@ -1271,7 +1273,7 @@
}
},
"channelPath_unknownPath": "Inconnu",
"channelPath_floodPath": "Inondation",
"channelPath_floodPath": "Tout le réseau",
"channelPath_directPath": "Afficher",
"channelPath_observedZeroOf": "0 de {total} sauts",
"@channelPath_observedZeroOf": {
@ -1336,6 +1338,7 @@
"listFilter_roomServers": "Serveurs de pièce",
"listFilter_unreadOnly": "Messages non lus seulement",
"listFilter_newGroup": "Nouvelle groupe",
"@neighbors_errorLoading": {
"placeholders": {
"error": {
@ -1349,5 +1352,18 @@
"neighbors_RequestTimedOut": "Les voisins demandent un délai.",
"neighbors_errorLoading": "Erreur lors du chargement des voisins : {error}",
"neighbors_repeatersNeighbours": "Répéteurs Voisins",
"neighbors_noData": "Aucune donnée concernant les voisins disponible."
"neighbors_noData": "Aucune donnée concernant les voisins disponible.",
"channels_createPrivateChannelDesc": "Sécurisé avec une clé secrète.",
"channels_joinPrivateChannel": "Rejoindre un Canal Privé",
"channels_createPrivateChannel": "Créer un Canal Privé",
"channels_joinPrivateChannelDesc": "Entrer manuellement une clé secrète.",
"channels_joinPublicChannel": "Rejoindre le canal public",
"channels_joinPublicChannelDesc": "Tout le monde peut rejoindre ce canal.",
"channels_joinHashtagChannel": "Rejoindre un Canal Hashtag",
"channels_joinHashtagChannelDesc": "N'importe qui peut rejoindre les canaux #hashtag.",
"channels_scanQrCode": "Scanner un code QR",
"channels_scanQrCodeComingSoon": "Bientôt disponible",
"channels_enterHashtag": "Entrez le hashtag",
"channels_hashtagHint": "ex. #équipe"
}

View file

@ -821,6 +821,8 @@
}
}
},
"login_failedMessage": "Accesso fallito. La password non è corretta oppure il ripetitore non è raggiungibile.",
"common_reload": "Ricaricare",
"common_clear": "Cancella",
"path_currentPath": "Percorso corrente: {path}",
@ -1336,6 +1338,7 @@
"listFilter_roomServers": "Server della stanza",
"listFilter_unreadOnly": "Solo non letto",
"listFilter_newGroup": "Nuovo gruppo",
"@neighbors_errorLoading": {
"placeholders": {
"error": {
@ -1349,5 +1352,18 @@
"neighbors_RequestTimedOut": "I vicini richiedono un timeout.",
"neighbors_errorLoading": "Errore nel caricamento dei vicini: {error}",
"neighbors_repeatersNeighbours": "Ripetitori Vicini",
"neighbors_noData": "Nessun dato sugli vicini disponibile."
"neighbors_noData": "Nessun dato sugli vicini disponibile.",
"channels_createPrivateChannel": "Crea un Canale Privato",
"channels_createPrivateChannelDesc": "Protetta con una chiave segreta.",
"channels_joinPrivateChannel": "Unisciti a un Canale Privato",
"channels_joinPrivateChannelDesc": "Inserire manualmente una chiave segreta.",
"channels_joinPublicChannel": "Unisciti al Canale Pubblico",
"channels_joinPublicChannelDesc": "Chiunque può unirsi a questo canale.",
"channels_joinHashtagChannel": "Unisciti a un Canale con Hashtag",
"channels_joinHashtagChannelDesc": "Chiunque può unirsi ai canali hashtag.",
"channels_scanQrCode": "Scansiona un codice QR",
"channels_scanQrCodeComingSoon": "Arriverà presto",
"channels_enterHashtag": "Inserisci hashtag",
"channels_hashtagHint": "es. #team"
}

View file

@ -1596,6 +1596,78 @@ abstract class AppLocalizations {
/// **'Unread'**
String get channels_sortUnread;
/// No description provided for @channels_createPrivateChannel.
///
/// In en, this message translates to:
/// **'Create a Private Channel'**
String get channels_createPrivateChannel;
/// No description provided for @channels_createPrivateChannelDesc.
///
/// In en, this message translates to:
/// **'Secured with a secret key.'**
String get channels_createPrivateChannelDesc;
/// No description provided for @channels_joinPrivateChannel.
///
/// In en, this message translates to:
/// **'Join a Private Channel'**
String get channels_joinPrivateChannel;
/// No description provided for @channels_joinPrivateChannelDesc.
///
/// In en, this message translates to:
/// **'Manually enter a secret key.'**
String get channels_joinPrivateChannelDesc;
/// No description provided for @channels_joinPublicChannel.
///
/// In en, this message translates to:
/// **'Join the Public Channel'**
String get channels_joinPublicChannel;
/// No description provided for @channels_joinPublicChannelDesc.
///
/// In en, this message translates to:
/// **'Anyone can join this channel.'**
String get channels_joinPublicChannelDesc;
/// No description provided for @channels_joinHashtagChannel.
///
/// In en, this message translates to:
/// **'Join a Hashtag Channel'**
String get channels_joinHashtagChannel;
/// No description provided for @channels_joinHashtagChannelDesc.
///
/// In en, this message translates to:
/// **'Anyone can join hashtag channels.'**
String get channels_joinHashtagChannelDesc;
/// No description provided for @channels_scanQrCode.
///
/// In en, this message translates to:
/// **'Scan a QR Code'**
String get channels_scanQrCode;
/// No description provided for @channels_scanQrCodeComingSoon.
///
/// In en, this message translates to:
/// **'Coming soon'**
String get channels_scanQrCodeComingSoon;
/// No description provided for @channels_enterHashtag.
///
/// In en, this message translates to:
/// **'Enter hashtag'**
String get channels_enterHashtag;
/// No description provided for @channels_hashtagHint.
///
/// In en, this message translates to:
/// **'e.g. #team'**
String get channels_hashtagHint;
/// No description provided for @chat_noMessages.
///
/// In en, this message translates to:
@ -2687,6 +2759,12 @@ abstract class AppLocalizations {
/// **'Login failed: {error}'**
String login_failed(String error);
/// No description provided for @login_failedMessage.
///
/// In en, this message translates to:
/// **'Login failed. Either the password is incorrect or the repeater is unreachable.'**
String get login_failedMessage;
/// No description provided for @common_reload.
///
/// In en, this message translates to:

View file

@ -830,6 +830,45 @@ class AppLocalizationsBg extends AppLocalizations {
@override
String get channels_sortUnread => 'Непрочетено';
@override
String get channels_createPrivateChannel => 'Създай Частен Канал';
@override
String get channels_createPrivateChannelDesc => 'Защитено с таен ключ.';
@override
String get channels_joinPrivateChannel => 'Присъедини се към Частен Канал';
@override
String get channels_joinPrivateChannelDesc => 'Ръчно въведете таен ключ.';
@override
String get channels_joinPublicChannel =>
'Присъединете се към Публичния канал';
@override
String get channels_joinPublicChannelDesc =>
'Всеки може да се присъедини към този канал.';
@override
String get channels_joinHashtagChannel => 'Присъедини се към Хаштаг Канал';
@override
String get channels_joinHashtagChannelDesc =>
'Всеки може да се присъедини към хаштаговите канали.';
@override
String get channels_scanQrCode => 'Сканирайте QR код';
@override
String get channels_scanQrCodeComingSoon => 'Ще излезе скоро';
@override
String get channels_enterHashtag => 'Въведете хаштаг';
@override
String get channels_hashtagHint => 'напр. #отбор';
@override
String get chat_noMessages => 'Няма съобщения.';
@ -1475,6 +1514,10 @@ class AppLocalizationsBg extends AppLocalizations {
return 'Входът не беше успешен: $error';
}
@override
String get login_failedMessage =>
'Входът не беше успешен. Или паролата е грешна, или повторителят е недостъпен.';
@override
String get common_reload => 'Презареди';

View file

@ -141,7 +141,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get scanner_scan => 'Scannen';
@override
String get device_quickSwitch => 'Schneller Umschalten';
String get device_quickSwitch => 'Schnelles Umschalten';
@override
String get device_meshcore => 'MeshCore';
@ -169,7 +169,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get settings_nodeNameNotSet => 'Nicht festgelegt';
@override
String get settings_nodeNameHint => 'Gib den Knotenamen ein';
String get settings_nodeNameHint => 'Gebe den Knotenamen ein';
@override
String get settings_nodeNameUpdated => 'Name aktualisiert';
@ -207,18 +207,18 @@ class AppLocalizationsDe extends AppLocalizations {
String get settings_longitude => 'Längengrad';
@override
String get settings_privacyMode => 'Privatschutzzustand';
String get settings_privacyMode => 'Privatsphäreeinstellung';
@override
String get settings_privacyModeSubtitle =>
'Verstecken Sie Name/Ort in Anzeigen';
'Verstecken Sie Name/Ort in Ankündigungen';
@override
String get settings_privacyModeToggle =>
'Aktivieren Sie den Datenschutzzustand, um Ihren Namen und Ihre Standortdaten in Anzeigen zu verbergen.';
'Aktivieren Sie die Privatsphäreeinstellung, um Ihren Namen und Ihre Standortdaten in Ankündigungen zu verbergen.';
@override
String get settings_privacyModeEnabled => 'Privatschutzzustand aktiviert';
String get settings_privacyModeEnabled => 'Datenschutzmodus aktiviert';
@override
String get settings_privacyModeDisabled => 'Datenschutzmodus deaktiviert';
@ -227,20 +227,20 @@ class AppLocalizationsDe extends AppLocalizations {
String get settings_actions => 'Aktionen';
@override
String get settings_sendAdvertisement => 'Senden Sie Anzeige';
String get settings_sendAdvertisement => 'Sende eine Ankündigung';
@override
String get settings_sendAdvertisementSubtitle => 'Sendungsstatus jetzt';
String get settings_sendAdvertisementSubtitle => 'Sende Ankündigung';
@override
String get settings_advertisementSent => 'Anzeige gesendet';
String get settings_advertisementSent => 'Ankündigung gesendet';
@override
String get settings_syncTime => 'Synchronisierungszeit';
String get settings_syncTime => 'Zeitsynchronisierung';
@override
String get settings_syncTimeSubtitle =>
'Stelle die Gerätewielfalt auf die Uhrzeit des Telefons ein';
'Stelle die Gerätezeit auf die Uhrzeit des Telefons ein';
@override
String get settings_timeSynchronized => 'Zeit synchronisiert';
@ -309,10 +309,10 @@ class AppLocalizationsDe extends AppLocalizations {
String get settings_infoPublicKey => 'Öffentlicher Schlüssel';
@override
String get settings_infoContactsCount => 'Kontakte Anzahl';
String get settings_infoContactsCount => 'Anzahl Kontakte';
@override
String get settings_infoChannelCount => 'Kanalanzahl';
String get settings_infoChannelCount => 'Anzahl Kanäle';
@override
String get settings_presets => 'Voreinstellungen';
@ -342,7 +342,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get settings_spreadingFactor => 'Verteilungsfaktor';
@override
String get settings_codingRate => 'Programmierpauschale';
String get settings_codingRate => 'Kodierungsrate';
@override
String get settings_txPower => 'TX-Leistung (dBm)';
@ -354,7 +354,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get settings_txPowerInvalid => 'Ungültige TX-Leistung (0-22 dBm)';
@override
String get settings_longRange => 'Langreich';
String get settings_longRange => 'Grosse Reichweite';
@override
String get settings_fastSpeed => 'Schnelle Geschwindigkeit';
@ -377,7 +377,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get appSettings_themeSystem => 'Systemstandard';
@override
String get appSettings_themeLight => 'Helligkeit';
String get appSettings_themeLight => 'Hell';
@override
String get appSettings_themeDark => 'Dunkel';
@ -435,7 +435,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get appSettings_enableNotificationsSubtitle =>
'Erhalte Benachrichtigungen für Nachrichten und Anzeigen';
'Erhalte Benachrichtigungen für Nachrichten und Ankündigungen';
@override
String get appSettings_notificationPermissionDenied =>
@ -450,15 +450,15 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get appSettings_messageNotifications =>
'Nachrichtenbenachrichtigungen';
'Direktnachrichten Benachrichtigungen';
@override
String get appSettings_messageNotificationsSubtitle =>
'Zeige Benachrichtigung beim Empfang neuer Nachrichten';
'Zeige Benachrichtigung beim Empfang neuer Direktnachrichten';
@override
String get appSettings_channelMessageNotifications =>
'Kanal-Nachrichten-Benachrichtigungen';
'Kanalnachrichten Benachrichtigungen';
@override
String get appSettings_channelMessageNotificationsSubtitle =>
@ -466,7 +466,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get appSettings_advertisementNotifications =>
'Werbeanzeigenbenachrichtigungen';
'Ankündigungsbenachrichtigungen';
@override
String get appSettings_advertisementNotificationsSubtitle =>
@ -477,11 +477,11 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get appSettings_clearPathOnMaxRetry =>
'Klares Pfad bei Max Wiederholungsversuch';
'Lösche Pfade bei Max Wiederholungsversuchen';
@override
String get appSettings_clearPathOnMaxRetrySubtitle =>
'Zurücksetzen des Kontaktpfads nach 5 fehlgeschlagenen Sendeverboten';
'Zurücksetzen der Kontaktpfade nach 5 fehlgeschlagenen Sendeabbrüchen';
@override
String get appSettings_pathsWillBeCleared =>
@ -566,17 +566,17 @@ class AppLocalizationsDe extends AppLocalizations {
}
@override
String get appSettings_mapTimeFilter => 'Kartent Zeitfilter';
String get appSettings_mapTimeFilter => 'Karten Zeitfilter';
@override
String get appSettings_showNodesDiscoveredWithin =>
'Zeige Knoten, die innerhalb von:';
@override
String get appSettings_allTime => 'Alle Zeit';
String get appSettings_allTime => 'Ganzer Zeitverlauf';
@override
String get appSettings_lastHour => 'Letzter Stunde';
String get appSettings_lastHour => 'Letzte Stunde';
@override
String get appSettings_last6Hours => 'Letzte 6 Stunden';
@ -620,48 +620,48 @@ class AppLocalizationsDe extends AppLocalizations {
String get contacts_title => 'Kontakte';
@override
String get contacts_noContacts => 'No Contacts noch';
String get contacts_noContacts => 'Noch keine Kontakte vorhanden.';
@override
String get contacts_contactsWillAppear =>
'Kontakte werden angezeigt, wenn Geräte Werbung machen.';
'Kontakte werden angezeigt, wenn Geräte eine Ankündigung machen.';
@override
String get contacts_searchContacts => 'Suche Kontakte...';
@override
String get contacts_noUnreadContacts => 'Keine ungeklärten Kontakte';
String get contacts_noUnreadContacts => 'Keine ungesehene Kontakte';
@override
String get contacts_noContactsFound =>
'Keine Kontakte oder Gruppen gefunden.';
@override
String get contacts_deleteContact => 'Löschen Sie Kontakt';
String get contacts_deleteContact => 'Lösche den Kontakt';
@override
String contacts_removeConfirm(String contactName) {
return 'Entfernen $contactName aus den Kontakten?';
return '$contactName aus den Kontakten entfernen?';
}
@override
String get contacts_manageRepeater => 'Wiederholung verwalten';
String get contacts_manageRepeater => 'Wiederholungen verwalten';
@override
String get contacts_roomLogin => 'Raum-Login';
@override
String get contacts_openChat => 'Öffnen Sie Chat';
String get contacts_openChat => 'Öffne Chat';
@override
String get contacts_editGroup => 'Gruppen bearbeiten';
String get contacts_editGroup => 'Gruppe bearbeiten';
@override
String get contacts_deleteGroup => 'Löschen Gruppe';
@override
String contacts_deleteGroupConfirm(String groupName) {
return 'Löschen Sie \"$groupName\"?';
return 'Löschen von \"$groupName\"?';
}
@override
@ -689,11 +689,11 @@ class AppLocalizationsDe extends AppLocalizations {
String get contacts_noMembers => 'Keine Mitglieder';
@override
String get contacts_lastSeenNow => 'Letztes Ansehen jetzt';
String get contacts_lastSeenNow => 'gerade gesehen';
@override
String contacts_lastSeenMinsAgo(int minutes) {
return 'Letzte Sichtung $minutes Minuten her.';
return 'Letzte Sichtung vor $minutes Minuten.';
}
@override
@ -701,7 +701,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String contacts_lastSeenHoursAgo(int hours) {
return 'Letzte Aktivität vor $hours Stunden.';
return 'Letzte Sichtung vor $hours Stunden.';
}
@override
@ -751,11 +751,11 @@ class AppLocalizationsDe extends AppLocalizations {
String get channels_editChannel => 'Kanal bearbeiten';
@override
String get channels_deleteChannel => 'Löschen Sie Kanal';
String get channels_deleteChannel => 'Lösche den Kanal';
@override
String channels_deleteChannelConfirm(String name) {
return 'Löschen \"$name\"? Dies kann nicht rückgängig gemacht werden.';
return 'Löschen von \"$name\"? Dies kann nicht rückgängig gemacht werden.';
}
@override
@ -799,7 +799,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String channels_editChannelTitle(int index) {
return 'Bearbeiteten Kanal $index';
return 'Bearbeiteter Kanal $index';
}
@override
@ -817,7 +817,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get channels_sortBy => 'Sortiere nach';
@override
String get channels_sortManual => 'Manuelle';
String get channels_sortManual => 'Manuell';
@override
String get channels_sortAZ => 'A bis Z';
@ -826,7 +826,49 @@ class AppLocalizationsDe extends AppLocalizations {
String get channels_sortLatestMessages => 'Letzte Nachrichten';
@override
String get channels_sortUnread => 'Unlescht';
String get channels_sortUnread => 'Ungelesen';
@override
String get channels_createPrivateChannel => 'Erstelle einen privaten Kanal';
@override
String get channels_createPrivateChannelDesc =>
'Verschlüsselt mit einem geheimen Schlüssel.';
@override
String get channels_joinPrivateChannel =>
'Treten Sie einem privaten Kanal bei';
@override
String get channels_joinPrivateChannelDesc =>
'Manuelle Eingabe eines geheimen Schlüssels.';
@override
String get channels_joinPublicChannel => 'Tritt dem öffentlichen Kanal bei';
@override
String get channels_joinPublicChannelDesc =>
'Jeder kann diesem Kanal beitreten.';
@override
String get channels_joinHashtagChannel =>
'Treten Sie einem Hashtag-Kanal bei';
@override
String get channels_joinHashtagChannelDesc =>
'Jeder kann sich bei Hashtag-Kanälen beteiligen.';
@override
String get channels_scanQrCode => 'Scannen Sie einen QR-Code';
@override
String get channels_scanQrCodeComingSoon => 'Bald verfügbar';
@override
String get channels_enterHashtag => 'Gib Hashtag ein';
@override
String get channels_hashtagHint => 'z.B. #team';
@override
String get chat_noMessages => 'Noch keine Nachrichten.';
@ -844,7 +886,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String chat_replyTo(String name) {
return 'Antworten Sie $name';
return 'Antwort an $name';
}
@override
@ -874,7 +916,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String chat_retryCount(int current, int max) {
return 'Versuchen $current/$max';
return 'Versuche $current/$max';
}
@override
@ -908,14 +950,13 @@ class AppLocalizationsDe extends AppLocalizations {
String get gifPicker_searchHint => 'Suche nach GIFs...';
@override
String get gifPicker_poweredBy => 'Angetrieben von GIPHY';
String get gifPicker_poweredBy => 'Bereitgestellt von GIPHY';
@override
String get gifPicker_noGifsFound => 'Keine GIFs gefunden';
@override
String get gifPicker_failedLoad =>
'GIF-Dateien konnten nicht geladen werden.';
String get gifPicker_failedLoad => 'GIF-Datei konnten nicht geladen werden.';
@override
String get gifPicker_failedSearch => 'Suche nach GIFs fehlgeschlagen';
@ -930,10 +971,10 @@ class AppLocalizationsDe extends AppLocalizations {
String get debugLog_bleTitle => 'BLE-Debug-Protokoll';
@override
String get debugLog_copyLog => 'Kopieren Sie Protokoll';
String get debugLog_copyLog => 'Kopieren des Protokolls';
@override
String get debugLog_clearLog => 'Log löschen';
String get debugLog_clearLog => 'Protokoll löschen';
@override
String get debugLog_copied => 'Debug-Protokoll kopiert';
@ -955,7 +996,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get debugLog_rawLogRx => 'Roh-Log-RX';
@override
String get debugLog_noBleActivity => 'No BLE-Aktivität bisher';
String get debugLog_noBleActivity => 'Bisher keine BLE-Aktivität';
@override
String debugFrame_length(int count) {
@ -1015,7 +1056,7 @@ class AppLocalizationsDe extends AppLocalizations {
'Automatisch (gespeicherten Pfad verwenden)';
@override
String get chat_forceFloodMode => 'Zwangsgelände-Modus erzwingen';
String get chat_forceFloodMode => 'Flut-Modus erzwingen';
@override
String get chat_recentAckPaths =>
@ -1026,31 +1067,31 @@ class AppLocalizationsDe extends AppLocalizations {
'Die Pfadhistorie ist voll. Entferne Einträge, um neue hinzuzufügen.';
@override
String get chat_hopSingular => 'Springe';
String get chat_hopSingular => 'Sprung';
@override
String get chat_hopPlural => 'Hops';
String get chat_hopPlural => 'Sprünge';
@override
String chat_hopsCount(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: 'Hops',
one: 'Hop',
other: 'Sprünge',
one: 'Sprung',
);
return '$count $_temp0';
}
@override
String get chat_successes => 'Erfolgreiche';
String get chat_successes => 'Erfolgreich';
@override
String get chat_removePath => 'Pfad entfernen';
@override
String get chat_noPathHistoryYet =>
'Noe eine Pfadhistorie vorhanden.\nSende eine Nachricht, um Pfade zu entdecken.';
'Keine eine Pfadhistorie vorhanden.\nSende eine Nachricht, um Pfade zu entdecken.';
@override
String get chat_pathActions => 'Pfadaktionen:';
@ -1059,26 +1100,25 @@ class AppLocalizationsDe extends AppLocalizations {
String get chat_setCustomPath => 'Lege benutzerdefinierten Pfad fest';
@override
String get chat_setCustomPathSubtitle => 'Manuelle Routenpfad festlegen';
String get chat_setCustomPathSubtitle => 'Manuellen Routenpfad festlegen';
@override
String get chat_clearPath => 'Klares Pfad';
String get chat_clearPath => 'Pfad zurücksetzen';
@override
String get chat_clearPathSubtitle =>
'Zwinge bei nächster Sendung eine erneute Entdeckung durch.';
'Setze Pfad zurück, erkenne neuen Pfad bei nächster Sendung.';
@override
String get chat_pathCleared =>
'Pfad freigelegt. Nächste Nachricht wird Route neu entdecken.';
'Pfad zurückgesetzt. Nächste Nachricht wird Route neu entdecken.';
@override
String get chat_floodModeSubtitle =>
'Verwende den Routingschalter in der App-Leiste';
@override
String get chat_floodModeEnabled =>
'Flutmodus aktiviert. Über den Routing-Icon in der App-Leiste wieder aktivieren.';
String get chat_floodModeEnabled => 'Flutmodus aktiviert.';
@override
String get chat_fullPath => 'Vollständiger Pfad';
@ -1100,7 +1140,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get chat_pathSavedLocally =>
'Gespeichert lokal. Mit Verbinden zum Synchronisieren.';
'Lokal Gespeichert. Bitte Verbinden zum Synchronisieren.';
@override
String get chat_pathDeviceConfirmed => 'Gerät bestätigt.';
@ -1109,7 +1149,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get chat_pathDeviceNotConfirmed => 'Gerät noch nicht bestätigt.';
@override
String get chat_type => 'Gib ein';
String get chat_type => 'Gebe ein';
@override
String get chat_path => 'Pfad';
@ -1119,13 +1159,13 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get chat_compressOutgoingMessages =>
'Komprimieren ausgehende Nachrichten';
'Komprimieren ausgehender Nachrichten';
@override
String get chat_floodForced => 'Überschwemmung (erzwungen)';
String get chat_floodForced => 'Geflutet (erzwungen)';
@override
String get chat_directForced => 'Direkt (gezwungen)';
String get chat_directForced => 'Direkt (erzwungen)';
@override
String chat_hopsForced(int count) {
@ -1133,28 +1173,28 @@ class AppLocalizationsDe extends AppLocalizations {
}
@override
String get chat_floodAuto => 'Überschwemmung (automatisch)';
String get chat_floodAuto => 'Geflutet (automatisch)';
@override
String get chat_direct => 'Direkt';
@override
String get chat_poiShared => 'Gemeinsamer POI';
String get chat_poiShared => 'Geteilter POI';
@override
String chat_unread(int count) {
return 'Unlescht: $count';
return 'Ungelesen: $count';
}
@override
String get map_title => 'Knotenkarte';
String get map_title => 'Karte';
@override
String get map_noNodesWithLocation => 'Keine Knoten mit Standortdaten';
@override
String get map_nodesNeedGps =>
'Knoten müssen ihre GPS-Koordinaten\nteilen,\num auf der Karte\nerscheinen.';
'Knoten müssen ihre GPS-Koordinaten teilen,\num auf der Karte zu erscheinen.';
@override
String map_nodesCount(int count) {
@ -1167,10 +1207,10 @@ class AppLocalizationsDe extends AppLocalizations {
}
@override
String get map_chat => 'Chat';
String get map_chat => 'Benutzer';
@override
String get map_repeater => 'Wiederholung';
String get map_repeater => 'Repeater';
@override
String get map_room => 'Raum';
@ -1179,13 +1219,13 @@ class AppLocalizationsDe extends AppLocalizations {
String get map_sensor => 'Sensor';
@override
String get map_pinDm => 'Sperren (DM)';
String get map_pinDm => 'Pin (Kontakt)';
@override
String get map_pinPrivate => 'Privat-Pin';
String get map_pinPrivate => 'Pin (Channel)';
@override
String get map_pinPublic => 'Öffentliche Taste (PIN)';
String get map_pinPublic => 'Pin (Public)';
@override
String get map_lastSeen => 'Letzte Sichtung';
@ -1201,13 +1241,13 @@ class AppLocalizationsDe extends AppLocalizations {
String get map_source => 'Quelle';
@override
String get map_flags => 'Flaggen';
String get map_flags => 'Flags';
@override
String get map_shareMarkerHere => 'Teilen Sie hier das Marker.';
String get map_shareMarkerHere => 'Teilen Sie den Marker hier.';
@override
String get map_pinLabel => 'Kennzeichnungslabel';
String get map_pinLabel => 'Pin Name';
@override
String get map_label => 'Label';
@ -1219,7 +1259,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get map_sendToContact => 'Senden an Kontakt';
@override
String get map_sendToChannel => 'Senden Sie Kanal';
String get map_sendToChannel => 'Senden an Kanal';
@override
String get map_noChannelsAvailable => 'Keine Kanäle verfügbar';
@ -1237,7 +1277,7 @@ class AppLocalizationsDe extends AppLocalizations {
'Verbinde ein Gerät, um Marker zu teilen';
@override
String get map_filterNodes => 'Filter Knoten';
String get map_filterNodes => 'Knotenfilter';
@override
String get map_nodeTypes => 'Knotentypen';
@ -1246,7 +1286,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get map_chatNodes => 'Chat-Knoten';
@override
String get map_repeaters => 'Wiederholer';
String get map_repeaters => 'Repeater';
@override
String get map_otherNodes => 'Andere Knoten';
@ -1258,7 +1298,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get map_filterByKeyPrefix => 'Filter nach Schlüsselpräfix';
@override
String get map_publicKeyPrefix => 'Öffentlicher Schlüsselpräfix';
String get map_publicKeyPrefix => 'Schlüsselpräfix';
@override
String get map_markers => 'Marker';
@ -1276,7 +1316,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get map_joinRoom => 'Beitreten Sie dem Raum';
@override
String get map_manageRepeater => 'Wiederholung verwalten';
String get map_manageRepeater => 'Repeater verwalten';
@override
String get mapCache_title => 'Offline-Karten-Cache';
@ -1287,14 +1327,14 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get mapCache_noTilesToDownload =>
'Keine Tiles für diese Region zum Herunterladen verfügbar.';
'Keine Kacheln für diese Region zum Herunterladen verfügbar.';
@override
String get mapCache_downloadTilesTitle => 'Herunterladen von Tiles';
String get mapCache_downloadTilesTitle => 'Herunterladen von Kacheln';
@override
String mapCache_downloadTilesPrompt(int count) {
return 'Laden $count Tiles für den Offline-Bereich herunter?';
return 'Laden $count Kacheln für den Offline-Bereich herunter?';
}
@override
@ -1302,16 +1342,16 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String mapCache_cachedTiles(int count) {
return 'Zwischengespeicherte $count Fliesen';
return 'Zwischengespeicherte $count Kacheln';
}
@override
String mapCache_cachedTilesWithFailed(int downloaded, int failed) {
return 'Zwischengespeicherte $downloaded Tiles ($failed fehlgeschlagen)';
return 'Zwischengespeicherte $downloaded Kacheln ($failed fehlgeschlagen)';
}
@override
String get mapCache_clearOfflineCacheTitle => 'Leeren Offline-Cache';
String get mapCache_clearOfflineCacheTitle => 'Leere Offline-Cache';
@override
String get mapCache_clearOfflineCachePrompt =>
@ -1343,7 +1383,7 @@ class AppLocalizationsDe extends AppLocalizations {
}
@override
String get mapCache_downloadTilesButton => 'Herunterladen von Tiles';
String get mapCache_downloadTilesButton => 'Herunterladen von Kacheln';
@override
String get mapCache_clearCacheButton => 'Cache leeren';
@ -1409,7 +1449,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get time_minutes => 'Minuten';
@override
String get time_allTime => 'Alle Zeit';
String get time_allTime => 'Ganzer Zeitraum';
@override
String get dialog_disconnect => 'Trennen';
@ -1419,7 +1459,7 @@ class AppLocalizationsDe extends AppLocalizations {
'Sind Sie sicher, dass Sie sich von diesem Gerät trennen möchten?';
@override
String get login_repeaterLogin => 'Wiederholungseingang anmelden';
String get login_repeaterLogin => 'Beim Repeater anmelden';
@override
String get login_roomLogin => 'Raum-Login';
@ -1456,7 +1496,7 @@ class AppLocalizationsDe extends AppLocalizations {
'Automatisch (gespeicherten Pfad verwenden)';
@override
String get login_forceFloodMode => 'Zwangsgelände-Modus erzwingen';
String get login_forceFloodMode => 'Flut-Modus erzwingen';
@override
String get login_managePaths => 'Pfadverwaltung';
@ -1474,6 +1514,10 @@ class AppLocalizationsDe extends AppLocalizations {
return 'Anmeldung fehlgeschlagen: $error';
}
@override
String get login_failedMessage =>
'Anmeldung fehlgeschlagen. Entweder ist das Passwort falsch oder der Repeater ist nicht erreichbar.';
@override
String get common_reload => 'Neu laden';
@ -1482,7 +1526,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String path_currentPath(String path) {
return 'Aktiger Pfad: $path';
return 'Aktiver Pfad: $path';
}
@override
@ -1497,14 +1541,14 @@ class AppLocalizationsDe extends AppLocalizations {
}
@override
String get path_enterCustomPath => 'Gib Pfad an';
String get path_enterCustomPath => 'Gebe Pfad ein';
@override
String get path_currentPathLabel => 'Aktueller Pfad';
@override
String get path_hexPrefixInstructions =>
'Gib für jeden Hopfen 2-stellige Hex-Präfixe ein, getrennt durch Kommas.';
'Gebe für jeden Hopfen 2-stellige Hex-Präfixe ein, getrennt durch Kommas.';
@override
String get path_hexPrefixExample =>
@ -1540,7 +1584,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get path_setPath => 'Pfad festlegen';
@override
String get repeater_management => 'Wiederholungselement-Verwaltung';
String get repeater_management => 'Repeater-Verwaltung';
@override
String get repeater_managementTools => 'Verwaltungs-Tools';
@ -1575,11 +1619,10 @@ class AppLocalizationsDe extends AppLocalizations {
String get repeater_settings => 'Einstellungen';
@override
String get repeater_settingsSubtitle =>
'Wiederholungsparameter konfigurieren';
String get repeater_settingsSubtitle => 'Repeater-parameter konfigurieren';
@override
String get repeater_statusTitle => 'Wiederholungszustand';
String get repeater_statusTitle => 'Repeaterstatus';
@override
String get repeater_routingMode => 'Routenmodus';
@ -1589,7 +1632,7 @@ class AppLocalizationsDe extends AppLocalizations {
'Automatisch (gespeicherten Pfad verwenden)';
@override
String get repeater_forceFloodMode => 'Zwangsgelände-Modus erzwingen';
String get repeater_forceFloodMode => 'Flut-Modus erzwingen';
@override
String get repeater_pathManagement => 'Pfadverwaltung';
@ -1685,13 +1728,13 @@ class AppLocalizationsDe extends AppLocalizations {
}
@override
String get repeater_settingsTitle => 'Wiederholungseinstellungen';
String get repeater_settingsTitle => 'Repeater Einstellungen';
@override
String get repeater_basicSettings => 'Grundlegende Einstellungen';
@override
String get repeater_repeaterName => 'Wiederholungseintrag';
String get repeater_repeaterName => 'Repeater Name';
@override
String get repeater_repeaterNameHelper => 'Anzeigename für diesen Repeater';
@ -1731,7 +1774,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get repeater_spreadingFactor => 'Verteilungsfaktor';
@override
String get repeater_codingRate => 'Programmierpauschale';
String get repeater_codingRate => 'Kodierungsrate';
@override
String get repeater_locationSettings => 'Standort Einstellungen';
@ -1766,17 +1809,18 @@ class AppLocalizationsDe extends AppLocalizations {
'Gast-Zugriff mit beschränkten Rechten zulassen';
@override
String get repeater_privacyMode => 'Privatschutzzustand';
String get repeater_privacyMode => 'Privatsphäreeinstellung';
@override
String get repeater_privacyModeSubtitle =>
'Verstecken Sie Name/Ort in Anzeigen';
'Verstecken Sie Name/Ort in Ankündigungen';
@override
String get repeater_advertisementSettings => 'Werbe Einstellungen';
String get repeater_advertisementSettings => 'Ankündigungseinstellungen';
@override
String get repeater_localAdvertInterval => 'Lokaler Werbeintervall';
String get repeater_localAdvertInterval =>
'Intervall der lokalen Ankündigungen';
@override
String repeater_localAdvertIntervalMinutes(int minutes) {
@ -1784,7 +1828,8 @@ class AppLocalizationsDe extends AppLocalizations {
}
@override
String get repeater_floodAdvertInterval => 'Überschwemmungsanzeige-Intervall';
String get repeater_floodAdvertInterval =>
'Intervall der gefluteten Ankündigungen';
@override
String repeater_floodAdvertIntervalHours(int hours) {
@ -1793,7 +1838,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get repeater_encryptedAdvertInterval =>
'Verschlüsselte Werbeintervall';
'Intervall der verschlüsselten Ankündigung';
@override
String get repeater_dangerZone => 'Gefahrenzone';
@ -1866,7 +1911,7 @@ class AppLocalizationsDe extends AppLocalizations {
'Radio-Einstellungen aktualisieren';
@override
String get repeater_refreshTxPower => 'Batterie-Strom aktualisieren';
String get repeater_refreshTxPower => 'Sendeleistung aktualisieren';
@override
String get repeater_refreshLocationSettings =>
@ -1885,7 +1930,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get repeater_refreshAdvertisementSettings =>
'Aktualisieren Sie die Werbe Einstellungen';
'Aktualisieren Sie die Ankündigungseinstellungen';
@override
String repeater_refreshed(String label) {
@ -1898,7 +1943,7 @@ class AppLocalizationsDe extends AppLocalizations {
}
@override
String get repeater_cliTitle => 'Wiederholung CLI';
String get repeater_cliTitle => 'Repeater CLI';
@override
String get repeater_debugNextCommand => 'Fehlersuche Nächster Befehl';
@ -1907,7 +1952,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get repeater_commandHelp => 'Hilfe';
@override
String get repeater_clearHistory => 'Löschung der Historie';
String get repeater_clearHistory => 'Löschen der Historie';
@override
String get repeater_noCommandsSent => 'Noch keine Befehle gesendet.';
@ -1952,13 +1997,13 @@ class AppLocalizationsDe extends AppLocalizations {
String get repeater_cliQuickVersion => 'Version';
@override
String get repeater_cliQuickAdvertise => 'Werben';
String get repeater_cliQuickAdvertise => 'Ankündigungen';
@override
String get repeater_cliQuickClock => 'Uhr';
@override
String get repeater_cliHelpAdvert => 'Sendet ein Werbepaket';
String get repeater_cliHelpAdvert => 'Sendet eine Ankündigung';
@override
String get repeater_cliHelpReboot =>
@ -1978,7 +2023,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get repeater_cliHelpClearStats =>
'Setzt verschiedene Statistikkalkulate auf Null zurück.';
'Setzt verschiedene Statistikberechnungen auf Null zurück.';
@override
String get repeater_cliHelpSetAf => 'Legt den Luftzeitfaktor fest.';
@ -1993,7 +2038,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get repeater_cliHelpSetAllowReadOnly =>
'(Raumspeicher) Wenn \'an\', dann wird die Anmeldung mit einem leeren Passwort erlaubt sein, aber kann nicht in den Raum geschickt werden. (nur lesen möglich).';
'(Raumspeicher) Wenn \'an\', dann wird die Anmeldung mit einem leeren Passwort erlaubt sein, aber es kann nicht in den Raum gesendet werden. (nur lesen möglich).';
@override
String get repeater_cliHelpSetFloodMax =>
@ -2013,11 +2058,11 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get repeater_cliHelpSetAdvertInterval =>
'Legt das Timer-Intervall in Minuten fest, um ein lokales (ohne-Weiterleitung) Werbe-Paket zu senden. Auf 0 setzen, um die Funktion zu deaktivieren.';
'Legt das Timer-Intervall in Minuten fest, um ein lokales (ohne-Weiterleitung) Ankündigungspaket zu senden. Auf 0 setzen, um die Funktion zu deaktivieren.';
@override
String get repeater_cliHelpSetFloodAdvertInterval =>
'Legt das Timer-Intervall in Stunden für den Versand eines Flut-Werbungspakets fest. Auf 0 setzen, um es zu deaktivieren.';
'Legt das Timer-Intervall in Stunden für den Versand eines Flut-Ankündigungspacket fest. Auf 0 setzen, um es zu deaktivieren.';
@override
String get repeater_cliHelpSetGuestPassword =>
@ -2028,11 +2073,11 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get repeater_cliHelpSetLat =>
'Legt die Breitengrad-Angabe der Werbekarte fest. (dezimale Grad)';
'Legt die Breitengrad der Ankündigung fest. (dezimale Grad)';
@override
String get repeater_cliHelpSetLon =>
'Legt die Längengrade der Werbe-Map fest. (dezimale Grad)';
'Legt die Längengrade der Ankündigung fest. (dezimale Grad)';
@override
String get repeater_cliHelpSetRadio =>
@ -2060,7 +2105,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get repeater_cliHelpSetBridgeSource =>
'Wählen Sie, ob die Brücke empfangene oder gesendete Pakete erneut übertragen soll.';
'Wählen Sie, ob über die Brücke empfangene oder gesendete Pakete erneut übertragen soll.';
@override
String get repeater_cliHelpSetBridgeBaud =>
@ -2068,7 +2113,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get repeater_cliHelpSetBridgeSecret =>
'Richte das Espnow-Brücken-Geheimnis ein.';
'Richte das Brückenpassword ein.';
@override
String get repeater_cliHelpSetAdcMultiplier =>
@ -2100,15 +2145,14 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get repeater_cliHelpNeighbors =>
'Zeigt eine Liste anderer Repeater-Knoten an, die über Zero-Hop-Werbung gehört wurden. Jede Zeile ist id-prefix-hex:timestamp:snr-times-4';
'Zeigt eine Liste anderer Repeater-Knoten an, die über Zero-Hop-Ankündigung gehört wurden. Jede Zeile ist id-prefix-hex:timestamp:snr-times-4';
@override
String get repeater_cliHelpNeighborRemove =>
'Entfernt das erste übereinstimmende Element (über Pubkey-Präfix (hex)) aus der Liste der Nachbarn.';
@override
String get repeater_cliHelpRegion =>
'(Serien nur) Listet alle definierten Regionen und aktuelle Hochwassermissungen auf.';
String get repeater_cliHelpRegion => 'Listet alle definierten Regionen auf.';
@override
String get repeater_cliHelpRegionLoad =>
@ -2287,7 +2331,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get channelPath_otherObservedPaths => 'Sonstige beobachtete Pfade';
@override
String get channelPath_repeaterHops => 'Wiederholungs-Sprünge';
String get channelPath_repeaterHops => 'Repeater-Sprünge';
@override
String get channelPath_noHopDetails =>
@ -2303,7 +2347,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get channelPath_timeLabel => 'Zeit';
@override
String get channelPath_repeatsLabel => 'Wiederholung';
String get channelPath_repeatsLabel => 'Wiederholungen';
@override
String channelPath_pathLabel(int index) {
@ -2335,7 +2379,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get channelPath_unknownPath => 'Unbekannt';
@override
String get channelPath_floodPath => 'Überschwemmung';
String get channelPath_floodPath => 'Geflutet';
@override
String get channelPath_directPath => 'Direkt';
@ -2390,7 +2434,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get listFilter_latestMessages => 'Letzte Nachrichten';
@override
String get listFilter_heardRecently => 'Hörte kürzlich';
String get listFilter_heardRecently => 'Kürzlich gehört';
@override
String get listFilter_az => 'A-Z';
@ -2405,7 +2449,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get listFilter_users => 'Benutzer';
@override
String get listFilter_repeaters => 'Wiederholer';
String get listFilter_repeaters => 'Repeater';
@override
String get listFilter_roomServers => 'Raumserver';

View file

@ -818,6 +818,43 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get channels_sortUnread => 'Unread';
@override
String get channels_createPrivateChannel => 'Create a Private Channel';
@override
String get channels_createPrivateChannelDesc => 'Secured with a secret key.';
@override
String get channels_joinPrivateChannel => 'Join a Private Channel';
@override
String get channels_joinPrivateChannelDesc => 'Manually enter a secret key.';
@override
String get channels_joinPublicChannel => 'Join the Public Channel';
@override
String get channels_joinPublicChannelDesc => 'Anyone can join this channel.';
@override
String get channels_joinHashtagChannel => 'Join a Hashtag Channel';
@override
String get channels_joinHashtagChannelDesc =>
'Anyone can join hashtag channels.';
@override
String get channels_scanQrCode => 'Scan a QR Code';
@override
String get channels_scanQrCodeComingSoon => 'Coming soon';
@override
String get channels_enterHashtag => 'Enter hashtag';
@override
String get channels_hashtagHint => 'e.g. #team';
@override
String get chat_noMessages => 'No messages yet';
@ -1453,6 +1490,10 @@ class AppLocalizationsEn extends AppLocalizations {
return 'Login failed: $error';
}
@override
String get login_failedMessage =>
'Login failed. Either the password is incorrect or the repeater is unreachable.';
@override
String get common_reload => 'Reload';

View file

@ -829,6 +829,46 @@ class AppLocalizationsEs extends AppLocalizations {
@override
String get channels_sortUnread => 'Sin leer';
@override
String get channels_createPrivateChannel => 'Crear un Canal Privado';
@override
String get channels_createPrivateChannelDesc =>
'Cifrado con una clave secreta.';
@override
String get channels_joinPrivateChannel => 'Únete a un Canal Privado';
@override
String get channels_joinPrivateChannelDesc =>
'Introducir manualmente una clave secreta.';
@override
String get channels_joinPublicChannel => 'Únete al Canal Público';
@override
String get channels_joinPublicChannelDesc =>
'Cualquiera puede unirse a este canal.';
@override
String get channels_joinHashtagChannel => 'Únete a un Canal con Hashtag';
@override
String get channels_joinHashtagChannelDesc =>
'Cualquiera puede unirse a los canales de hashtag.';
@override
String get channels_scanQrCode => 'Escanear un Código QR';
@override
String get channels_scanQrCodeComingSoon => 'Próximamente';
@override
String get channels_enterHashtag => 'Introducir hashtag';
@override
String get channels_hashtagHint => 'ej. #equipo';
@override
String get chat_noMessages => 'Aún no hay mensajes';
@ -1472,6 +1512,10 @@ class AppLocalizationsEs extends AppLocalizations {
return 'Inicio fallido: $error';
}
@override
String get login_failedMessage =>
'Inicio fallido. La contraseña es incorrecta o el repetidor no está disponible.';
@override
String get common_reload => 'Recargar';

View file

@ -211,11 +211,11 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get settings_privacyModeSubtitle =>
'Cacher le nom/l\'emplacement dans les publicités';
'Cacher le nom/l\'emplacement dans les annonces';
@override
String get settings_privacyModeToggle =>
'Activer le mode confidentialité pour masquer votre nom et votre localisation dans les publicités.';
'Activer le mode confidentialité pour masquer votre nom et votre localisation dans les annonces.';
@override
String get settings_privacyModeEnabled => 'Mode de confidentialité activé';
@ -228,7 +228,7 @@ class AppLocalizationsFr extends AppLocalizations {
String get settings_actions => 'Actions';
@override
String get settings_sendAdvertisement => 'Envoyer la publicité';
String get settings_sendAdvertisement => 'S\'annoncer';
@override
String get settings_sendAdvertisementSubtitle =>
@ -438,7 +438,7 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get appSettings_enableNotificationsSubtitle =>
'Recevoir des notifications pour les messages et les publicités';
'Recevoir des notifications pour les messages et les annonces';
@override
String get appSettings_notificationPermissionDenied =>
@ -467,7 +467,7 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get appSettings_advertisementNotifications =>
'Notifications publicitaires';
'Notifications d\'annonces';
@override
String get appSettings_advertisementNotificationsSubtitle =>
@ -498,7 +498,7 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get appSettings_autoRouteRotationSubtitle =>
'Alterner entre les meilleurs chemins et le mode inondation';
'Alterner entre les meilleurs chemins et le mode d\'envoi sur tout le réseau (flood)';
@override
String get appSettings_autoRouteRotationEnabled =>
@ -830,6 +830,46 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get channels_sortUnread => 'Non lu';
@override
String get channels_createPrivateChannel => 'Créer un Canal Privé';
@override
String get channels_createPrivateChannelDesc =>
'Sécurisé avec une clé secrète.';
@override
String get channels_joinPrivateChannel => 'Rejoindre un Canal Privé';
@override
String get channels_joinPrivateChannelDesc =>
'Entrer manuellement une clé secrète.';
@override
String get channels_joinPublicChannel => 'Rejoindre le canal public';
@override
String get channels_joinPublicChannelDesc =>
'Tout le monde peut rejoindre ce canal.';
@override
String get channels_joinHashtagChannel => 'Rejoindre un Canal Hashtag';
@override
String get channels_joinHashtagChannelDesc =>
'N\'importe qui peut rejoindre les canaux #hashtag.';
@override
String get channels_scanQrCode => 'Scanner un code QR';
@override
String get channels_scanQrCodeComingSoon => 'Bientôt disponible';
@override
String get channels_enterHashtag => 'Entrez le hashtag';
@override
String get channels_hashtagHint => 'ex. #équipe';
@override
String get chat_noMessages => 'Aucun message pour le moment.';
@ -1016,7 +1056,7 @@ class AppLocalizationsFr extends AppLocalizations {
String get chat_autoUseSavedPath => 'Auto (utiliser le chemin sauvegardé)';
@override
String get chat_forceFloodMode => 'Mode Inondation Forcée';
String get chat_forceFloodMode => 'Mode tout le réseau forcé';
@override
String get chat_recentAckPaths =>
@ -1080,7 +1120,7 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get chat_floodModeEnabled =>
'Le mode inondation est activé. Réactiver via l\'icône de routage dans la barre d\'outils.';
'Le mode envoi à tout le réseau est activé. Changer via l\'icône de routage dans la barre d\'outils.';
@override
String get chat_fullPath => 'Chemin complet';
@ -1125,7 +1165,7 @@ class AppLocalizationsFr extends AppLocalizations {
'Compresser les messages sortants';
@override
String get chat_floodForced => 'Inondation (forcée)';
String get chat_floodForced => 'Tout le réseau (forcée)';
@override
String get chat_directForced => 'Direct (forcé)';
@ -1136,7 +1176,7 @@ class AppLocalizationsFr extends AppLocalizations {
}
@override
String get chat_floodAuto => 'Inondation (auto)';
String get chat_floodAuto => 'Tout le réseau (auto)';
@override
String get chat_direct => 'Afficher';
@ -1460,7 +1500,7 @@ class AppLocalizationsFr extends AppLocalizations {
String get login_autoUseSavedPath => 'Auto (utiliser le chemin sauvegardé)';
@override
String get login_forceFloodMode => 'Mode Inondation Forcée';
String get login_forceFloodMode => 'Mode tout le réseau forcé';
@override
String get login_managePaths => 'Gérer les chemins';
@ -1478,6 +1518,10 @@ class AppLocalizationsFr extends AppLocalizations {
return 'Connexion échouée : $error';
}
@override
String get login_failedMessage =>
'Connexion échouée. Soit le mot de passe est incorrect, soit le relais est injoignable.';
@override
String get common_reload => 'Recharger';
@ -1594,7 +1638,7 @@ class AppLocalizationsFr extends AppLocalizations {
'Auto (utiliser le chemin sauvegardé)';
@override
String get repeater_forceFloodMode => 'Mode de submersion forcée';
String get repeater_forceFloodMode => 'Mode tout le réseau forcé';
@override
String get repeater_pathManagement => 'Gestion des chemins';
@ -1671,17 +1715,17 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String repeater_packetTxTotal(int total, String flood, String direct) {
return 'Total : $total, Inondation : $flood, Direct : $direct';
return 'Total : $total, Tout le réseau : $flood, Direct : $direct';
}
@override
String repeater_packetRxTotal(int total, String flood, String direct) {
return 'Total : $total, Inondation : $flood, Direct : $direct';
return 'Total : $total, Tout le réseau : $flood, Direct : $direct';
}
@override
String repeater_duplicatesFloodDirect(String flood, String direct) {
return 'Inondation : $flood, Direct : $direct';
return 'Tout le réseau : $flood, Direct : $direct';
}
@override
@ -1777,13 +1821,14 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get repeater_privacyModeSubtitle =>
'Cacher le nom/l\'emplacement dans les publicités';
'Cacher le nom/l\'emplacement dans les annonces';
@override
String get repeater_advertisementSettings => 'Paramètres de Publicité';
String get repeater_advertisementSettings => 'Paramètres d\'annonces';
@override
String get repeater_localAdvertInterval => 'Intervalle Publicité Locale';
String get repeater_localAdvertInterval =>
'Intervalle des annonces Locale (0 saut)';
@override
String repeater_localAdvertIntervalMinutes(int minutes) {
@ -1792,7 +1837,7 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get repeater_floodAdvertInterval =>
'Intervalle de Publicité Inondation';
'Intervalle des annonces à tout le réseau (flood)';
@override
String repeater_floodAdvertIntervalHours(int hours) {
@ -1801,7 +1846,7 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get repeater_encryptedAdvertInterval =>
'Intervalle publicitaire crypté';
'Intervalle d\'annonces cryptées';
@override
String get repeater_dangerZone => 'Zone d\'alerte';
@ -1892,7 +1937,7 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get repeater_refreshAdvertisementSettings =>
'Rafraîchir les Paramètres de la Publicité';
'Rafraîchir les Paramètres des annonces';
@override
String repeater_refreshed(String label) {
@ -1966,7 +2011,7 @@ class AppLocalizationsFr extends AppLocalizations {
String get repeater_cliQuickClock => 'Horloge';
@override
String get repeater_cliHelpAdvert => 'Envoie un paquet publicitaire';
String get repeater_cliHelpAdvert => 'Envoie un paquet d\'annonce';
@override
String get repeater_cliHelpReboot =>
@ -2032,7 +2077,7 @@ class AppLocalizationsFr extends AppLocalizations {
'Définit/met à jour le mot de passe de l\'invité. (pour les répéteurs, les connexions d\'invités peuvent envoyer la requête \"Get Stats\")';
@override
String get repeater_cliHelpSetName => 'Définit le nom de la publicité.';
String get repeater_cliHelpSetName => 'Définit le nom de l\'annonce.';
@override
String get repeater_cliHelpSetLat =>
@ -2052,7 +2097,7 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get repeater_cliHelpSetTxDelay =>
'Définit un facteur multiplié par le temps de fonctionnement en mode inondation pour un paquet et avec un système de slot aléatoire, afin de retarder son envoi (pour diminuer la probabilité de collisions).';
'Définit un facteur multiplié par le temps de fonctionnement en mode vers tout le réseau (flood) pour un paquet et avec un système de slot aléatoire, afin de retarder son envoi (pour diminuer la probabilité de collisions).';
@override
String get repeater_cliHelpSetDirectTxDelay =>
@ -2107,7 +2152,7 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get repeater_cliHelpNeighbors =>
'Affiche une liste d\'autres nœuds répétiteurs entendus via des publicités sans relais. Chaque ligne est id-préfixe-hexadécimal:timestamp:snr-fois-4';
'Affiche une liste d\'autres nœuds répétiteurs entendus via des annonces sans relais. Chaque ligne est id-préfixe-hexadécimal:timestamp:snr-fois-4';
@override
String get repeater_cliHelpNeighborRemove =>
@ -2115,7 +2160,7 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get repeater_cliHelpRegion =>
'(série uniquement) Liste toutes les régions définies et les autorisations de débordement actuelles.';
'(série uniquement) Liste toutes les régions définies et les autorisations actuelles d\'annonces sur tout le réseau (flood).';
@override
String get repeater_cliHelpRegionLoad =>
@ -2342,7 +2387,7 @@ class AppLocalizationsFr extends AppLocalizations {
String get channelPath_unknownPath => 'Inconnu';
@override
String get channelPath_floodPath => 'Inondation';
String get channelPath_floodPath => 'Tout le réseau';
@override
String get channelPath_directPath => 'Afficher';

View file

@ -827,6 +827,46 @@ class AppLocalizationsIt extends AppLocalizations {
@override
String get channels_sortUnread => 'Non letto';
@override
String get channels_createPrivateChannel => 'Crea un Canale Privato';
@override
String get channels_createPrivateChannelDesc =>
'Protetta con una chiave segreta.';
@override
String get channels_joinPrivateChannel => 'Unisciti a un Canale Privato';
@override
String get channels_joinPrivateChannelDesc =>
'Inserire manualmente una chiave segreta.';
@override
String get channels_joinPublicChannel => 'Unisciti al Canale Pubblico';
@override
String get channels_joinPublicChannelDesc =>
'Chiunque può unirsi a questo canale.';
@override
String get channels_joinHashtagChannel => 'Unisciti a un Canale con Hashtag';
@override
String get channels_joinHashtagChannelDesc =>
'Chiunque può unirsi ai canali hashtag.';
@override
String get channels_scanQrCode => 'Scansiona un codice QR';
@override
String get channels_scanQrCodeComingSoon => 'Arriverà presto';
@override
String get channels_enterHashtag => 'Inserisci hashtag';
@override
String get channels_hashtagHint => 'es. #team';
@override
String get chat_noMessages => 'Nessun messaggio ancora';
@ -1470,6 +1510,10 @@ class AppLocalizationsIt extends AppLocalizations {
return 'Accesso fallito: $error';
}
@override
String get login_failedMessage =>
'Accesso fallito. La password non è corretta oppure il ripetitore non è raggiungibile.';
@override
String get common_reload => 'Ricaricare';

View file

@ -15,7 +15,7 @@ class AppLocalizationsNl extends AppLocalizations {
String get nav_contacts => 'Contacten';
@override
String get nav_channels => 'Kanaal';
String get nav_channels => 'Kanalen';
@override
String get nav_map => 'Kaart';
@ -39,7 +39,7 @@ class AppLocalizationsNl extends AppLocalizations {
String get common_close => 'Sluiten';
@override
String get common_edit => 'Bewerk';
String get common_edit => 'Bewerken';
@override
String get common_add => 'Toevoegen';
@ -48,13 +48,13 @@ class AppLocalizationsNl extends AppLocalizations {
String get common_settings => 'Instellingen';
@override
String get common_disconnect => 'Verbinden verbreken';
String get common_disconnect => 'Verbinding verbreken';
@override
String get common_connected => 'Verbonden';
@override
String get common_disconnected => 'Ontkoppeld';
String get common_disconnected => 'Verbinding verbroken';
@override
String get common_create => 'Maak';
@ -78,7 +78,7 @@ class AppLocalizationsNl extends AppLocalizations {
String get common_remove => 'Verwijderen';
@override
String get common_enable => 'Aktivatie';
String get common_enable => 'Activeren';
@override
String get common_disable => 'Uitschakelen';
@ -87,7 +87,7 @@ class AppLocalizationsNl extends AppLocalizations {
String get common_reboot => 'Herstarten';
@override
String get common_loading => 'Laad...';
String get common_loading => 'Laden...';
@override
String get common_notAvailable => '';
@ -168,7 +168,7 @@ class AppLocalizationsNl extends AppLocalizations {
String get settings_nodeNameNotSet => 'Niet ingesteld';
@override
String get settings_nodeNameHint => 'Voer knooppuntnaam in';
String get settings_nodeNameHint => 'Voer nodenaam in';
@override
String get settings_nodeNameUpdated => 'Naam bijgewerkt';
@ -312,7 +312,7 @@ class AppLocalizationsNl extends AppLocalizations {
String get settings_infoContactsCount => 'Aantal Contacten';
@override
String get settings_infoChannelCount => 'Kanaal Aantal';
String get settings_infoChannelCount => 'Aantal Kanalen';
@override
String get settings_presets => 'Presets';
@ -354,10 +354,10 @@ class AppLocalizationsNl extends AppLocalizations {
String get settings_txPowerInvalid => 'Ongeldige TX-vermogen (0-22 dBm)';
@override
String get settings_longRange => 'Lang Bereik';
String get settings_longRange => 'Lange Afstand';
@override
String get settings_fastSpeed => 'Snelle Snelheid';
String get settings_fastSpeed => 'Hoge Snelheid';
@override
String settings_error(String message) {
@ -377,7 +377,7 @@ class AppLocalizationsNl extends AppLocalizations {
String get appSettings_themeSystem => 'Standaardinstelling';
@override
String get appSettings_themeLight => 'Helder';
String get appSettings_themeLight => 'Licht';
@override
String get appSettings_themeDark => 'Donker';
@ -469,13 +469,13 @@ class AppLocalizationsNl extends AppLocalizations {
@override
String get appSettings_advertisementNotificationsSubtitle =>
'Toon notificatie wanneer nieuwe knooppunten worden ontdekt';
'Toon notificatie wanneer nieuwe nodes worden ontdekt';
@override
String get appSettings_messaging => 'Berichten';
@override
String get appSettings_clearPathOnMaxRetry => 'Duidelijke Pad op Max Retry';
String get appSettings_clearPathOnMaxRetry => 'Wis Pad op Max Retry';
@override
String get appSettings_clearPathOnMaxRetrySubtitle =>
@ -490,19 +490,19 @@ class AppLocalizationsNl extends AppLocalizations {
'Padoms worden niet automatisch verwijderd';
@override
String get appSettings_autoRouteRotation => 'Automatische Route Rotatie';
String get appSettings_autoRouteRotation => 'Route Automatisch Roteren';
@override
String get appSettings_autoRouteRotationSubtitle =>
'Wissel tussen de beste paden en floodmodus over.';
'Verwissel tussen beste pad en floodmodus.';
@override
String get appSettings_autoRouteRotationEnabled =>
'Automatische routeplanning rotatie ingeschakeld';
'Automatische route rotatie ingeschakeld';
@override
String get appSettings_autoRouteRotationDisabled =>
'Automatische routeplanning rotatie is uitgeschakeld';
'Automatische route rotatie is uitgeschakeld';
@override
String get appSettings_battery => 'Batterij';
@ -532,11 +532,11 @@ class AppLocalizationsNl extends AppLocalizations {
String get appSettings_mapDisplay => 'Kaartweergave';
@override
String get appSettings_showRepeaters => 'Toon Herhalingen';
String get appSettings_showRepeaters => 'Toon Repeaters';
@override
String get appSettings_showRepeatersSubtitle =>
'Toon herhalende knoopjes op de kaart';
'Toon repeaternodes op de kaart';
@override
String get appSettings_showChatNodes => 'Chat Nodes tonen';
@ -546,21 +546,21 @@ class AppLocalizationsNl extends AppLocalizations {
'Chatnodes weergeven op de kaart';
@override
String get appSettings_showOtherNodes => 'Toon Andere Knopen';
String get appSettings_showOtherNodes => 'Toon Andere Nodes';
@override
String get appSettings_showOtherNodesSubtitle =>
'Toon andere knooptypes op de kaart';
'Toon andere nodetypes op de kaart';
@override
String get appSettings_timeFilter => 'Filter op tijd';
@override
String get appSettings_timeFilterShowAll => 'Alle knooppunten tonen';
String get appSettings_timeFilterShowAll => 'Alle nodes tonen';
@override
String appSettings_timeFilterShowLast(int hours) {
return 'Toon knopen van de laatste $hours uur';
return 'Toon nodes van de laatste $hours uur';
}
@override
@ -568,10 +568,10 @@ class AppLocalizationsNl extends AppLocalizations {
@override
String get appSettings_showNodesDiscoveredWithin =>
'Toon knooppunten ontdekt binnen:';
'Toon nodes ontdekt binnen:';
@override
String get appSettings_allTime => 'Alle tijd';
String get appSettings_allTime => 'Altijd';
@override
String get appSettings_lastHour => 'Laat uur';
@ -642,7 +642,7 @@ class AppLocalizationsNl extends AppLocalizations {
}
@override
String get contacts_manageRepeater => 'Beheer Herhaling';
String get contacts_manageRepeater => 'Beheer Repeater';
@override
String get contacts_roomLogin => 'Ruimte Inloggen';
@ -690,7 +690,7 @@ class AppLocalizationsNl extends AppLocalizations {
@override
String contacts_lastSeenMinsAgo(int minutes) {
return 'Laast gezien $minutes minuten geleden';
return 'Laatst gezien $minutes minuten geleden';
}
@override
@ -824,6 +824,46 @@ class AppLocalizationsNl extends AppLocalizations {
@override
String get channels_sortUnread => 'Ongelezen';
@override
String get channels_createPrivateChannel => 'Maak een Privé Kanaal';
@override
String get channels_createPrivateChannelDesc =>
'Beveiligd met een geheime sleutel.';
@override
String get channels_joinPrivateChannel => 'Sluit een Privé Kanaal aan';
@override
String get channels_joinPrivateChannelDesc =>
'Handmatig een geheime sleutel invoeren.';
@override
String get channels_joinPublicChannel => 'Sluit het Open Kanaal';
@override
String get channels_joinPublicChannelDesc =>
'Iedereen kan dit kanaal aanmelden.';
@override
String get channels_joinHashtagChannel => 'Sluit een Hashtag Kanaal';
@override
String get channels_joinHashtagChannelDesc =>
'Iedereen kan lid worden van hashtag-kanalen.';
@override
String get channels_scanQrCode => 'Scan een QR-code';
@override
String get channels_scanQrCodeComingSoon => 'Komt later';
@override
String get channels_enterHashtag => 'Voer hashtag in';
@override
String get channels_hashtagHint => 'bijv. #team';
@override
String get chat_noMessages => 'Nog geen berichten.';
@ -1009,7 +1049,7 @@ class AppLocalizationsNl extends AppLocalizations {
String get chat_autoUseSavedPath => 'Automatisch (gebruik opgeslagen pad)';
@override
String get chat_forceFloodMode => 'Dwing Overstromingsmodus';
String get chat_forceFloodMode => 'Dwing Floodsmodus';
@override
String get chat_recentAckPaths => 'Recente ACK Paden (tik om te gebruiken):';
@ -1071,7 +1111,7 @@ class AppLocalizationsNl extends AppLocalizations {
@override
String get chat_floodModeEnabled =>
'Overstromingsmodus is ingeschakeld. Schakel dit uit via het route-icoon in de app-balk.';
'Floodmodus is ingeschakeld. Schakel dit uit via het route-icoon in de app-balk.';
@override
String get chat_fullPath => 'Volledige Pad';
@ -1115,18 +1155,18 @@ class AppLocalizationsNl extends AppLocalizations {
'Verzenden van uitgaande berichten comprimeren';
@override
String get chat_floodForced => 'Overstroming (gedwongen)';
String get chat_floodForced => 'Flood (afgedwongen)';
@override
String get chat_directForced => 'Direct (gedwongen)';
String get chat_directForced => 'Direct (afgedwongen)';
@override
String chat_hopsForced(int count) {
return '$count sprongen (gedwongen)';
return '$count hops (afgedwongen)';
}
@override
String get chat_floodAuto => 'Overstroming (auto)';
String get chat_floodAuto => 'Flood (auto)';
@override
String get chat_direct => 'Direct';
@ -1143,7 +1183,7 @@ class AppLocalizationsNl extends AppLocalizations {
String get map_title => 'Node Map';
@override
String get map_noNodesWithLocation => 'Geen knopen met locatiegegevens';
String get map_noNodesWithLocation => 'Geen nodes met locatiegegevens';
@override
String get map_nodesNeedGps =>
@ -1163,7 +1203,7 @@ class AppLocalizationsNl extends AppLocalizations {
String get map_chat => 'Chat';
@override
String get map_repeater => 'Herhaling';
String get map_repeater => 'Repeater';
@override
String get map_room => 'Ruimte';
@ -1230,19 +1270,19 @@ class AppLocalizationsNl extends AppLocalizations {
'Verbind met een apparaat om markers te delen';
@override
String get map_filterNodes => 'Filter Knopen';
String get map_filterNodes => 'Filter Nodes';
@override
String get map_nodeTypes => 'Node Types';
String get map_nodeTypes => 'Nodetypes';
@override
String get map_chatNodes => 'Chat Nodes';
String get map_chatNodes => 'Chatnodes';
@override
String get map_repeaters => 'Herhalingen';
String get map_repeaters => 'Repeaters';
@override
String get map_otherNodes => 'Andere knooppunten';
String get map_otherNodes => 'Andere Nodes';
@override
String get map_keyPrefix => 'Prefix sleutel';
@ -1269,7 +1309,7 @@ class AppLocalizationsNl extends AppLocalizations {
String get map_joinRoom => 'Sluit Kamer';
@override
String get map_manageRepeater => 'Beheer Herhaling';
String get map_manageRepeater => 'Beheer Repeater';
@override
String get mapCache_title => 'Offline Kaarten Cache';
@ -1412,7 +1452,7 @@ class AppLocalizationsNl extends AppLocalizations {
'Ben je er zeker van dat je verbinding met dit apparaat wilt verbreken?';
@override
String get login_repeaterLogin => 'Herhaalders Inloggen';
String get login_repeaterLogin => 'Inloggen Repeater';
@override
String get login_roomLogin => 'Ruimte Inloggen';
@ -1432,7 +1472,7 @@ class AppLocalizationsNl extends AppLocalizations {
@override
String get login_repeaterDescription =>
'Voer het wachtwoord van de herhaling in om instellingen en status te openen.';
'Voer het wachtwoord van de repeater in om instellingen en status te openen.';
@override
String get login_roomDescription =>
@ -1448,7 +1488,7 @@ class AppLocalizationsNl extends AppLocalizations {
String get login_autoUseSavedPath => 'Automatisch (gebruik opgeslagen pad)';
@override
String get login_forceFloodMode => 'Dwing Overstromingsmodus';
String get login_forceFloodMode => 'Dwing Floodmodus Af';
@override
String get login_managePaths => 'Padbeheer';
@ -1466,6 +1506,10 @@ class AppLocalizationsNl extends AppLocalizations {
return 'Inloggen mislukt: $error';
}
@override
String get login_failedMessage =>
'Inloggen mislukt. Het wachtwoord is onjuist of de repeater is niet bereikbaar.';
@override
String get common_reload => 'Opnieuw laden';
@ -1513,8 +1557,7 @@ class AppLocalizationsNl extends AppLocalizations {
String get path_selectFromContacts => 'Of select contacten:';
@override
String get path_noRepeatersFound =>
'Geen herhalingen of zaalservers gevonden.';
String get path_noRepeatersFound => 'Geen repeaters of roomservers gevonden.';
@override
String get path_customPathsRequire =>
@ -1533,7 +1576,7 @@ class AppLocalizationsNl extends AppLocalizations {
String get path_setPath => 'Stel Pad in';
@override
String get repeater_management => 'Beheer Herhalingen';
String get repeater_management => 'Beheer Repeaters';
@override
String get repeater_managementTools => 'Beheerinstrumenten';
@ -1556,7 +1599,7 @@ class AppLocalizationsNl extends AppLocalizations {
String get repeater_cli => 'CLI';
@override
String get repeater_cliSubtitle => 'Verzend commando\'s naar de herhaaldere';
String get repeater_cliSubtitle => 'Verzend commando\'s naar de repeater';
@override
String get repeater_neighbours => 'Neighbors';
@ -1571,7 +1614,7 @@ class AppLocalizationsNl extends AppLocalizations {
String get repeater_settingsSubtitle => 'Configureer repeaterparameters';
@override
String get repeater_statusTitle => 'Status herhalen';
String get repeater_statusTitle => 'Status repeater';
@override
String get repeater_routingMode => 'Routeerwijze';
@ -1581,7 +1624,7 @@ class AppLocalizationsNl extends AppLocalizations {
'Automatisch (gebruik opgeslagen pad)';
@override
String get repeater_forceFloodMode => 'Dwing Overloopmodus';
String get repeater_forceFloodMode => 'Dwing Floodmodus Af';
@override
String get repeater_pathManagement => 'Beheer van paden';
@ -1598,7 +1641,7 @@ class AppLocalizationsNl extends AppLocalizations {
}
@override
String get repeater_systemInformation => 'Systeem Informatie';
String get repeater_systemInformation => 'Systeeminformatie';
@override
String get repeater_battery => 'Batterij';
@ -1613,10 +1656,10 @@ class AppLocalizationsNl extends AppLocalizations {
String get repeater_queueLength => 'Wachttijd';
@override
String get repeater_debugFlags => 'Debug Flags';
String get repeater_debugFlags => 'Debugvlaggen';
@override
String get repeater_radioStatistics => 'Radio Statistieken';
String get repeater_radioStatistics => 'Radiostatistieken';
@override
String get repeater_lastRssi => 'Laatste RSSI';
@ -1625,7 +1668,7 @@ class AppLocalizationsNl extends AppLocalizations {
String get repeater_lastSnr => 'Laatste SNR';
@override
String get repeater_noiseFloor => 'Ruishoordniveau';
String get repeater_noiseFloor => 'Ruisvloer';
@override
String get repeater_txAirtime => 'TX Airtime';
@ -1634,7 +1677,7 @@ class AppLocalizationsNl extends AppLocalizations {
String get repeater_rxAirtime => 'RX Airtime';
@override
String get repeater_packetStatistics => 'Pakket Statistieken';
String get repeater_packetStatistics => 'Pakketstatistieken';
@override
String get repeater_sent => 'Verzonden';
@ -1643,7 +1686,7 @@ class AppLocalizationsNl extends AppLocalizations {
String get repeater_received => 'Ontvangen';
@override
String get repeater_duplicates => 'Dubbele';
String get repeater_duplicates => 'Duplicaat';
@override
String repeater_daysHoursMinsSecs(
@ -1657,17 +1700,17 @@ class AppLocalizationsNl extends AppLocalizations {
@override
String repeater_packetTxTotal(int total, String flood, String direct) {
return 'Totaal: $total, Overstroming: $flood, Direct: $direct';
return 'Totaal: $total, Flood: $flood, Direct: $direct';
}
@override
String repeater_packetRxTotal(int total, String flood, String direct) {
return 'Totaal: $total, Overstroming: $flood, Direct: $direct';
return 'Totaal: $total, Flood: $flood, Direct: $direct';
}
@override
String repeater_duplicatesFloodDirect(String flood, String direct) {
return 'Overstroming: $flood, Direct: $direct';
return 'Flood: $flood, Direct: $direct';
}
@override
@ -1676,16 +1719,16 @@ class AppLocalizationsNl extends AppLocalizations {
}
@override
String get repeater_settingsTitle => 'Herstelinstellingen';
String get repeater_settingsTitle => 'Repeater Instellingen';
@override
String get repeater_basicSettings => 'Basisinstellingen';
@override
String get repeater_repeaterName => 'Herhaalnaam';
String get repeater_repeaterName => 'Repeaternaam';
@override
String get repeater_repeaterNameHelper => 'Weergave naam voor deze herhaling';
String get repeater_repeaterNameHelper => 'Weergave naam voor deze repeater';
@override
String get repeater_adminPassword => 'Admin wachtwoord';
@ -1718,7 +1761,7 @@ class AppLocalizationsNl extends AppLocalizations {
String get repeater_bandwidth => 'Bandbreedte';
@override
String get repeater_spreadingFactor => 'Spreadsnelheid';
String get repeater_spreadingFactor => 'Spreidingsfactor';
@override
String get repeater_codingRate => 'Codeertarief';
@ -1742,11 +1785,11 @@ class AppLocalizationsNl extends AppLocalizations {
String get repeater_features => 'Kenmerken';
@override
String get repeater_packetForwarding => 'Pakketdoorstrooming';
String get repeater_packetForwarding => 'Pakketdoorvoering';
@override
String get repeater_packetForwardingSubtitle =>
'Herstel activeren om pakketten door te sturen';
'Repeater instellen om pakketten door te sturen';
@override
String get repeater_guestAccess => 'Toegang voor Gasten';
@ -1756,7 +1799,7 @@ class AppLocalizationsNl extends AppLocalizations {
'Toegestane leesbeheer toegang voor gasten.';
@override
String get repeater_privacyMode => 'Privacy Mode';
String get repeater_privacyMode => 'Privacy Modus';
@override
String get repeater_privacyModeSubtitle =>
@ -1774,8 +1817,7 @@ class AppLocalizationsNl extends AppLocalizations {
}
@override
String get repeater_floodAdvertInterval =>
'Advertentie Interval bij overstroming';
String get repeater_floodAdvertInterval => 'Flood Advertentie Interval';
@override
String repeater_floodAdvertIntervalHours(int hours) {
@ -1790,11 +1832,10 @@ class AppLocalizationsNl extends AppLocalizations {
String get repeater_dangerZone => 'Gevaarzone';
@override
String get repeater_rebootRepeater => 'Herstart Herhaalder';
String get repeater_rebootRepeater => 'Herstart Repeater';
@override
String get repeater_rebootRepeaterSubtitle =>
'De herstart van het herhalerapparaat';
String get repeater_rebootRepeaterSubtitle => 'Herstart het Repeaterapparaat';
@override
String get repeater_rebootRepeaterConfirm =>
@ -1810,18 +1851,18 @@ class AppLocalizationsNl extends AppLocalizations {
@override
String get repeater_regenerateIdentityKeyConfirm =>
'Dit genereert een nieuwe identiteit voor de herhaling. Doorgaan?';
'Dit genereert een nieuwe identiteit voor de repeater. Doorgaan?';
@override
String get repeater_eraseFileSystem => 'Verwijder Besturingssysteem';
@override
String get repeater_eraseFileSystemSubtitle =>
'Formateer het herhalende bestandsysteem';
'Formateer het bestandsysteem van de repeater';
@override
String get repeater_eraseFileSystemConfirm =>
'WAARSCHUWING: Dit zal alle gegevens op de herhaling wissen. Dit kan niet worden teruggedraaid!';
'WAARSCHUWING: Dit zal alle gegevens op de repeater wissen. Dit kan niet worden teruggedraaid!';
@override
String get repeater_eraseSerialOnly =>
@ -1853,7 +1894,7 @@ class AppLocalizationsNl extends AppLocalizations {
@override
String get repeater_refreshRadioSettings =>
'Radiozenders Instellingen Bijwerken';
'Radiozender Instellingen Verversen';
@override
String get repeater_refreshTxPower => 'Nieuw laden TX-vermogen';
@ -1887,7 +1928,7 @@ class AppLocalizationsNl extends AppLocalizations {
}
@override
String get repeater_cliTitle => 'Herhaling CLI';
String get repeater_cliTitle => 'Repeater CLI';
@override
String get repeater_debugNextCommand => 'Debug Volgende Commando';
@ -1978,7 +2019,7 @@ class AppLocalizationsNl extends AppLocalizations {
@override
String get repeater_cliHelpSetRepeat =>
'Activeert of deactiveert de herhalerrol voor dit knoop.';
'Activeert of deactiveert de repeater rol van deze node.';
@override
String get repeater_cliHelpSetAllowReadOnly =>
@ -1986,7 +2027,7 @@ class AppLocalizationsNl extends AppLocalizations {
@override
String get repeater_cliHelpSetFloodMax =>
'Stelt het maximale aantal hops van een inkomend overlastpakket in (indien >= max, wordt het pakket niet doorgestuurd)';
'Stelt het maximale aantal hops van een inkomend floodpakket in (indien >= max, wordt het pakket niet doorgestuurd)';
@override
String get repeater_cliHelpSetIntThresh =>
@ -1998,7 +2039,7 @@ class AppLocalizationsNl extends AppLocalizations {
@override
String get repeater_cliHelpSetMultiAcks =>
'Activeert of deactiveert de functie \'dubbele ACKs\'.';
'Activeert of deactiveert de functie \'duplicate ACKs\'.';
@override
String get repeater_cliHelpSetAdvertInterval =>
@ -2006,7 +2047,7 @@ class AppLocalizationsNl extends AppLocalizations {
@override
String get repeater_cliHelpSetFloodAdvertInterval =>
'Stelt het timerinterval in uren in om een overstromingsadvertentiepakket te versturen. Stel in op 0 om dit uit te schakelen.';
'Stelt het timerinterval in uren in om een floodadvertentiepakket te versturen. Stel in op 0 om dit uit te schakelen.';
@override
String get repeater_cliHelpSetGuestPassword =>
@ -2097,7 +2138,7 @@ class AppLocalizationsNl extends AppLocalizations {
@override
String get repeater_cliHelpRegion =>
'(reeks alleen) Lijst alle gedefinieerde regio\'s en huidige overstromingsrechten.';
'(Alleen Serieel) Lijst alle gedefinieerde regio\'s en huidige floodrechten.';
@override
String get repeater_cliHelpRegionLoad =>
@ -2142,11 +2183,11 @@ class AppLocalizationsNl extends AppLocalizations {
String get repeater_cliHelpGpsOnOff => 'Schakel de GPS-standby aan/uit.';
@override
String get repeater_cliHelpGpsSync => 'Synchroniseer knooptime met GPS-klok.';
String get repeater_cliHelpGpsSync => 'Synchroniseer node met GPS-klok.';
@override
String get repeater_cliHelpGpsSetLoc =>
'Stel de positie van het knoop vast naar GPS-coördinaten en sla de voorkeuren op.';
'Stel de positie van de node vast als GPS-coördinaten en sla de voorkeuren op.';
@override
String get repeater_cliHelpGpsAdvert =>
@ -2176,11 +2217,11 @@ class AppLocalizationsNl extends AppLocalizations {
String get repeater_logging => 'Logging';
@override
String get repeater_neighborsRepeaterOnly => 'Buren (Alleen herhaald)';
String get repeater_neighborsRepeaterOnly => 'Buren (Alleen repeaters)';
@override
String get repeater_regionManagementRepeaterOnly =>
'Regiobeheer (Alleen voor Repeater)';
'Regiobeheer (Alleen Repeater)';
@override
String get repeater_regionNote =>
@ -2274,7 +2315,7 @@ class AppLocalizationsNl extends AppLocalizations {
String get channelPath_otherObservedPaths => 'Overige Waargenomen Paden';
@override
String get channelPath_repeaterHops => 'Herhalingstapjes';
String get channelPath_repeaterHops => 'Repeater Hops';
@override
String get channelPath_noHopDetails =>
@ -2290,7 +2331,7 @@ class AppLocalizationsNl extends AppLocalizations {
String get channelPath_timeLabel => 'Tijd';
@override
String get channelPath_repeatsLabel => 'Herhalen';
String get channelPath_repeatsLabel => 'Repeats';
@override
String channelPath_pathLabel(int index) {
@ -2322,7 +2363,7 @@ class AppLocalizationsNl extends AppLocalizations {
String get channelPath_unknownPath => 'Onbekend';
@override
String get channelPath_floodPath => 'Overstroming';
String get channelPath_floodPath => 'Flood';
@override
String get channelPath_directPath => 'Direct';
@ -2342,7 +2383,7 @@ class AppLocalizationsNl extends AppLocalizations {
@override
String get channelPath_noRepeaterLocations =>
'Geen herhaler locaties beschikbaar voor deze route.';
'Geen repeaters beschikbaar voor deze route.';
@override
String channelPath_primaryPath(int index) {
@ -2365,7 +2406,7 @@ class AppLocalizationsNl extends AppLocalizations {
'Geen details beschikbaar voor dit pakket.';
@override
String get channelPath_unknownRepeater => 'Onbekend Herhaalaar';
String get channelPath_unknownRepeater => 'Onbekend Repeater';
@override
String get listFilter_tooltip => 'Filteren en sorteren';
@ -2392,10 +2433,10 @@ class AppLocalizationsNl extends AppLocalizations {
String get listFilter_users => 'Gebruikers';
@override
String get listFilter_repeaters => 'Herhalingen';
String get listFilter_repeaters => 'Repeaters';
@override
String get listFilter_roomServers => 'Kamervirtualisatie';
String get listFilter_roomServers => 'Roomservers';
@override
String get listFilter_unreadOnly => 'Alleen ongelezen';

View file

@ -828,6 +828,46 @@ class AppLocalizationsPl extends AppLocalizations {
@override
String get channels_sortUnread => 'Niezgłoszone';
@override
String get channels_createPrivateChannel => 'Utwórz Prywatny Kanał';
@override
String get channels_createPrivateChannelDesc =>
'Zabezpieczone kluczem szyfrowym.';
@override
String get channels_joinPrivateChannel => 'Dołącz do Prywatnego Kanału';
@override
String get channels_joinPrivateChannelDesc => 'Ręcznie wprowadź klucz tajny.';
@override
String get channels_joinPublicChannel => 'Dołącz do kanału publicznego.';
@override
String get channels_joinPublicChannelDesc =>
'Każdy może dołączyć do tego kanału.';
@override
String get channels_joinHashtagChannel =>
'Dołącz do kanału oznaczanego hashtagiem';
@override
String get channels_joinHashtagChannelDesc =>
'Każdy może dołączyć do kanałów z hashtagami.';
@override
String get channels_scanQrCode => 'Skanuj kod QR';
@override
String get channels_scanQrCodeComingSoon => 'Wkrótce';
@override
String get channels_enterHashtag => 'Wprowadź hashtag';
@override
String get channels_hashtagHint => 'np. #zespół';
@override
String get chat_noMessages => 'Brak jeszcze wiadomości';
@ -1474,6 +1514,10 @@ class AppLocalizationsPl extends AppLocalizations {
return 'Zalogowanie się nie powiodło: $error';
}
@override
String get login_failedMessage =>
'Logowanie nie powiodło się. Hasło jest nieprawidłowe albo repeater jest nieosiągalny.';
@override
String get common_reload => 'Ponownie załadować';

View file

@ -829,6 +829,46 @@ class AppLocalizationsPt extends AppLocalizations {
@override
String get channels_sortUnread => 'Não lido';
@override
String get channels_createPrivateChannel => 'Criar um Canal Privado';
@override
String get channels_createPrivateChannelDesc =>
'Protegido com uma chave secreta.';
@override
String get channels_joinPrivateChannel => 'Junte-se a um Canal Privado';
@override
String get channels_joinPrivateChannelDesc =>
'Inserir uma chave secreta manualmente.';
@override
String get channels_joinPublicChannel => 'Junte-se ao Canal Público';
@override
String get channels_joinPublicChannelDesc =>
'Qualquer pessoa pode entrar neste canal.';
@override
String get channels_joinHashtagChannel => 'Junte-se a um Canal com Hashtag';
@override
String get channels_joinHashtagChannelDesc =>
'Qualquer pessoa pode participar de canais com hashtag.';
@override
String get channels_scanQrCode => 'Digitalizar um Código QR';
@override
String get channels_scanQrCodeComingSoon => 'Em breve';
@override
String get channels_enterHashtag => 'Insira hashtag';
@override
String get channels_hashtagHint => 'ex. #equipe';
@override
String get chat_noMessages => 'Ainda não existem mensagens.';
@ -1472,6 +1512,10 @@ class AppLocalizationsPt extends AppLocalizations {
return 'Login falhou: $error';
}
@override
String get login_failedMessage =>
'Falha no login. A senha está incorreta ou o repetidor está inacessível.';
@override
String get common_reload => 'Recarregar';

View file

@ -824,6 +824,45 @@ class AppLocalizationsSk extends AppLocalizations {
@override
String get channels_sortUnread => 'Nezriadené';
@override
String get channels_createPrivateChannel => 'Vytvorte súkromný kanál';
@override
String get channels_createPrivateChannelDesc =>
'Zabezpečené pomocou tajného kľúča.';
@override
String get channels_joinPrivateChannel => 'Pripojiť sa k súkromnému kanálu';
@override
String get channels_joinPrivateChannelDesc => 'Ručne zadajte tajný kľúč.';
@override
String get channels_joinPublicChannel => 'Pripojte sa k verejnému kanálu';
@override
String get channels_joinPublicChannelDesc =>
'Któvek sátó na tutó kanalizovát.';
@override
String get channels_joinHashtagChannel => 'Pripojte sa k Hashtag Kanálu';
@override
String get channels_joinHashtagChannelDesc =>
'Ktoekolikoľvek sa môže pridať do hashtag kanálov.';
@override
String get channels_scanQrCode => 'Skenujte QR kód';
@override
String get channels_scanQrCodeComingSoon => 'Čoskoro';
@override
String get channels_enterHashtag => 'Zadajte hashtag';
@override
String get channels_hashtagHint => 'napr. #tím';
@override
String get chat_noMessages => 'Zatiaľ žiadne správy.';
@ -1468,6 +1507,10 @@ class AppLocalizationsSk extends AppLocalizations {
return 'Prihlásenie zlyhalo: $error';
}
@override
String get login_failedMessage =>
'Prihlásenie zlyhalo. Heslo je nesprávne alebo je opakovač nedostupný.';
@override
String get common_reload => 'Načítať';

View file

@ -824,6 +824,45 @@ class AppLocalizationsSl extends AppLocalizations {
@override
String get channels_sortUnread => 'Nerešeno';
@override
String get channels_createPrivateChannel => 'Ustvari zasebno kanal.';
@override
String get channels_createPrivateChannelDesc =>
'Varno zaklenjeno s skrivnim ključem.';
@override
String get channels_joinPrivateChannel => 'Pridružite se zasebni skupini';
@override
String get channels_joinPrivateChannelDesc => 'Ročno vnesite zaporni ključ.';
@override
String get channels_joinPublicChannel => 'Pridružite se javnemu kanalu';
@override
String get channels_joinPublicChannelDesc =>
'Kdor karkoli je, lahko se pridruži tej skupini.';
@override
String get channels_joinHashtagChannel => 'Pridružite se Kanalu z Hashtagom';
@override
String get channels_joinHashtagChannelDesc =>
'Kdor karkoli, lahko se pridruži hashtag kanalom.';
@override
String get channels_scanQrCode => 'Skeniraj QR kodo';
@override
String get channels_scanQrCodeComingSoon => 'Prihajajoča';
@override
String get channels_enterHashtag => 'Vnesite hashtag';
@override
String get channels_hashtagHint => 'npr. #ekipa';
@override
String get chat_noMessages => 'Še ni sporočil.';
@ -1469,6 +1508,10 @@ class AppLocalizationsSl extends AppLocalizations {
return 'Prijava je bila neuspešna: $error';
}
@override
String get login_failedMessage =>
'Prijava je bila neuspešna. Geslo je napačno ali pa je repetitor nedosegljiv.';
@override
String get common_reload => 'Ponovno naloži';

View file

@ -817,6 +817,46 @@ class AppLocalizationsSv extends AppLocalizations {
@override
String get channels_sortUnread => 'Oläst';
@override
String get channels_createPrivateChannel => 'Skapa en privat kanal';
@override
String get channels_createPrivateChannelDesc =>
'Skyddat med en hemlig nyckel.';
@override
String get channels_joinPrivateChannel => 'Gå med i en Privat Kanal';
@override
String get channels_joinPrivateChannelDesc =>
'Ange en hemlig nyckel manuellt.';
@override
String get channels_joinPublicChannel => 'Gå med i den Offentliga Kanalen';
@override
String get channels_joinPublicChannelDesc =>
'Vem som helst kan gå med i denna kanal.';
@override
String get channels_joinHashtagChannel => 'Gå med i en Hashtagkanal';
@override
String get channels_joinHashtagChannelDesc =>
'Väldigt enkelt att gå med i hashtag-kanaler.';
@override
String get channels_scanQrCode => 'Skanna en QR-kod';
@override
String get channels_scanQrCodeComingSoon => 'Kommer snart';
@override
String get channels_enterHashtag => 'Ange hashtag';
@override
String get channels_hashtagHint => 't.ex. #team';
@override
String get chat_noMessages => 'Inga meddelanden ännu';
@ -1457,6 +1497,10 @@ class AppLocalizationsSv extends AppLocalizations {
return 'Inloggning misslyckades: $error';
}
@override
String get login_failedMessage =>
'Inloggning misslyckades. Antingen är lösenordet fel eller så går det inte att nå repeatern.';
@override
String get common_reload => 'Ladda om';

View file

@ -789,6 +789,42 @@ class AppLocalizationsZh extends AppLocalizations {
@override
String get channels_sortUnread => '未读';
@override
String get channels_createPrivateChannel => '创建私聊频道';
@override
String get channels_createPrivateChannelDesc => '使用密钥保护。';
@override
String get channels_joinPrivateChannel => '加入私密频道';
@override
String get channels_joinPrivateChannelDesc => '手动输入密钥。';
@override
String get channels_joinPublicChannel => '加入公共频道';
@override
String get channels_joinPublicChannelDesc => '任何人都可以加入这个频道。';
@override
String get channels_joinHashtagChannel => '加入标签频道';
@override
String get channels_joinHashtagChannelDesc => '任何人都可以加入话题频道。';
@override
String get channels_scanQrCode => '扫描二维码';
@override
String get channels_scanQrCodeComingSoon => '即将到来';
@override
String get channels_enterHashtag => '输入标签';
@override
String get channels_hashtagHint => '例如 #团队';
@override
String get chat_noMessages => '目前还没有消息';
@ -1411,6 +1447,9 @@ class AppLocalizationsZh extends AppLocalizations {
return '登录失败:$error';
}
@override
String get login_failedMessage => '登录失败。密码不正确或中继器不可达。';
@override
String get common_reload => '重新加载';

View file

@ -2,7 +2,7 @@
"@@locale": "nl",
"appTitle": "MeshCore Open",
"nav_contacts": "Contacten",
"nav_channels": "Kanaal",
"nav_channels": "Kanalen",
"nav_map": "Kaart",
"common_cancel": "Annuleren",
"common_connect": "Verbinden",
@ -10,12 +10,12 @@
"common_save": "Opslaan",
"common_delete": "Verwijderen",
"common_close": "Sluiten",
"common_edit": "Bewerk",
"common_edit": "Bewerken",
"common_add": "Toevoegen",
"common_settings": "Instellingen",
"common_disconnect": "Verbinden verbreken",
"common_disconnect": "Verbinding verbreken",
"common_connected": "Verbonden",
"common_disconnected": "Ontkoppeld",
"common_disconnected": "Verbinding verbroken",
"common_create": "Maak",
"common_continue": "Doorgaan",
"common_share": "Delen",
@ -23,10 +23,10 @@
"common_retry": "Nogmaals proberen",
"common_hide": "Verbergen",
"common_remove": "Verwijderen",
"common_enable": "Aktivatie",
"common_enable": "Activeren",
"common_disable": "Uitschakelen",
"common_reboot": "Herstarten",
"common_loading": "Laad...",
"common_loading": "Laden...",
"common_notAvailable": "—",
"common_voltageValue": "{volts} V",
"@common_voltageValue": {
@ -78,7 +78,7 @@
"settings_nodeSettings": "Node Instellingen",
"settings_nodeName": "Node Naam",
"settings_nodeNameNotSet": "Niet ingesteld",
"settings_nodeNameHint": "Voer knooppuntnaam in",
"settings_nodeNameHint": "Voer nodenaam in",
"settings_nodeNameUpdated": "Naam bijgewerkt",
"settings_radioSettings": "Radio Instellingen",
"settings_radioSettingsSubtitle": "Frequentie, vermogen, spredfactor",
@ -129,7 +129,7 @@
"settings_infoBattery": "Batterij",
"settings_infoPublicKey": "Openbare Sleutel",
"settings_infoContactsCount": "Aantal Contacten",
"settings_infoChannelCount": "Kanaal Aantal",
"settings_infoChannelCount": "Aantal Kanalen",
"settings_presets": "Presets",
"settings_preset915Mhz": "915 MHz",
"settings_preset868Mhz": "868 MHz",
@ -143,8 +143,8 @@
"settings_txPower": "TX Vermogen (dBm)",
"settings_txPowerHelper": "0 - 22",
"settings_txPowerInvalid": "Ongeldige TX-vermogen (0-22 dBm)",
"settings_longRange": "Lang Bereik",
"settings_fastSpeed": "Snelle Snelheid",
"settings_longRange": "Lange Afstand",
"settings_fastSpeed": "Hoge Snelheid",
"settings_error": "Fout: {message}",
"@settings_error": {
"placeholders": {
@ -157,7 +157,7 @@
"appSettings_appearance": "Uiterlijk",
"appSettings_theme": "Thema",
"appSettings_themeSystem": "Standaardinstelling",
"appSettings_themeLight": "Helder",
"appSettings_themeLight": "Licht",
"appSettings_themeDark": "Donker",
"appSettings_language": "Taal",
"appSettings_languageSystem": "Standaardinstelling",
@ -185,16 +185,16 @@
"appSettings_channelMessageNotifications": "Kanaal Bericht Meldingen",
"appSettings_channelMessageNotificationsSubtitle": "Toon notificatie bij het ontvangen van kanaalberichten",
"appSettings_advertisementNotifications": "Advertentie-meldingen",
"appSettings_advertisementNotificationsSubtitle": "Toon notificatie wanneer nieuwe knooppunten worden ontdekt",
"appSettings_advertisementNotificationsSubtitle": "Toon notificatie wanneer nieuwe nodes worden ontdekt",
"appSettings_messaging": "Berichten",
"appSettings_clearPathOnMaxRetry": "Duidelijke Pad op Max Retry",
"appSettings_clearPathOnMaxRetry": "Wis Pad op Max Retry",
"appSettings_clearPathOnMaxRetrySubtitle": "Reset contactpad na 5 mislukte verzendpogingen",
"appSettings_pathsWillBeCleared": "De paden worden na 5 mislukte pogingen leeggehaald.",
"appSettings_pathsWillNotBeCleared": "Padoms worden niet automatisch verwijderd",
"appSettings_autoRouteRotation": "Automatische Route Rotatie",
"appSettings_autoRouteRotationSubtitle": "Wissel tussen de beste paden en floodmodus over.",
"appSettings_autoRouteRotationEnabled": "Automatische routeplanning rotatie ingeschakeld",
"appSettings_autoRouteRotationDisabled": "Automatische routeplanning rotatie is uitgeschakeld",
"appSettings_autoRouteRotation": "Route Automatisch Roteren",
"appSettings_autoRouteRotationSubtitle": "Verwissel tussen beste pad en floodmodus.",
"appSettings_autoRouteRotationEnabled": "Automatische route rotatie ingeschakeld",
"appSettings_autoRouteRotationDisabled": "Automatische route rotatie is uitgeschakeld",
"appSettings_battery": "Batterij",
"appSettings_batteryChemistry": "Batterijchemie",
"appSettings_batteryChemistryPerDevice": "Instellen per apparaat ({deviceName})",
@ -210,15 +210,15 @@
"appSettings_batteryLifepo4": "LiFePO4 (2,6-3,65V)",
"appSettings_batteryLipo": "LiPo (3,0-4,2V)",
"appSettings_mapDisplay": "Kaartweergave",
"appSettings_showRepeaters": "Toon Herhalingen",
"appSettings_showRepeatersSubtitle": "Toon herhalende knoopjes op de kaart",
"appSettings_showRepeaters": "Toon Repeaters",
"appSettings_showRepeatersSubtitle": "Toon repeaternodes op de kaart",
"appSettings_showChatNodes": "Chat Nodes tonen",
"appSettings_showChatNodesSubtitle": "Chatnodes weergeven op de kaart",
"appSettings_showOtherNodes": "Toon Andere Knopen",
"appSettings_showOtherNodesSubtitle": "Toon andere knooptypes op de kaart",
"appSettings_showOtherNodes": "Toon Andere Nodes",
"appSettings_showOtherNodesSubtitle": "Toon andere nodetypes op de kaart",
"appSettings_timeFilter": "Filter op tijd",
"appSettings_timeFilterShowAll": "Alle knooppunten tonen",
"appSettings_timeFilterShowLast": "Toon knopen van de laatste {hours} uur",
"appSettings_timeFilterShowAll": "Alle nodes tonen",
"appSettings_timeFilterShowLast": "Toon nodes van de laatste {hours} uur",
"@appSettings_timeFilterShowLast": {
"placeholders": {
"hours": {
@ -227,8 +227,8 @@
}
},
"appSettings_mapTimeFilter": "Filter tijd op kaart",
"appSettings_showNodesDiscoveredWithin": "Toon knooppunten ontdekt binnen:",
"appSettings_allTime": "Alle tijd",
"appSettings_showNodesDiscoveredWithin": "Toon nodes ontdekt binnen:",
"appSettings_allTime": "Altijd",
"appSettings_lastHour": "Laat uur",
"appSettings_last6Hours": "laatste 6 uur",
"appSettings_last24Hours": "De laatste 24 uur",
@ -266,7 +266,7 @@
}
}
},
"contacts_manageRepeater": "Beheer Herhaling",
"contacts_manageRepeater": "Beheer Repeater",
"contacts_roomLogin": "Ruimte Inloggen",
"contacts_openChat": "Open Chat",
"contacts_editGroup": "Groep bewerken",
@ -294,7 +294,7 @@
"contacts_noContactsMatchFilter": "Geen contacten matchen met uw filter",
"contacts_noMembers": "Geen leden",
"contacts_lastSeenNow": "Laatste keer gezien nu",
"contacts_lastSeenMinsAgo": "Laast gezien {minutes} minuten geleden",
"contacts_lastSeenMinsAgo": "Laatst gezien {minutes} minuten geleden",
"@contacts_lastSeenMinsAgo": {
"placeholders": {
"minutes": {
@ -539,7 +539,7 @@
"chat_pathManagement": "Beheer van Paden",
"chat_routingMode": "Routeerwijze",
"chat_autoUseSavedPath": "Automatisch (gebruik opgeslagen pad)",
"chat_forceFloodMode": "Dwing Overstromingsmodus",
"chat_forceFloodMode": "Dwing Floodsmodus",
"chat_recentAckPaths": "Recente ACK Paden (tik om te gebruiken):",
"chat_pathHistoryFull": "De voorgeschiedenis is vol. Verwijder vermeldingen om er nieuwe aan toe te voegen.",
"chat_hopSingular": "Hop",
@ -562,7 +562,7 @@
"chat_clearPathSubtitle": "Dwing herontdekking bij volgende verzending",
"chat_pathCleared": "Pad is vrijgegeven. Volgende bericht herontdekt route.",
"chat_floodModeSubtitle": "Gebruik de route-schakelaar in de app-balk",
"chat_floodModeEnabled": "Overstromingsmodus is ingeschakeld. Schakel dit uit via het route-icoon in de app-balk.",
"chat_floodModeEnabled": "Floodmodus is ingeschakeld. Schakel dit uit via het route-icoon in de app-balk.",
"chat_fullPath": "Volledige Pad",
"chat_pathDetailsNotAvailable": "De paddetails zijn nog niet beschikbaar. Probeer een bericht te sturen om te vernieuwen.",
"chat_pathSetHops": "Pad ingesteld: {hopCount} {hopCount, plural, =1{hop} other{hops}} - {status}",
@ -583,9 +583,9 @@
"chat_path": "Pad",
"chat_publicKey": "Openbare Sleutel",
"chat_compressOutgoingMessages": "Verzenden van uitgaande berichten comprimeren",
"chat_floodForced": "Overstroming (gedwongen)",
"chat_directForced": "Direct (gedwongen)",
"chat_hopsForced": "{count} sprongen (gedwongen)",
"chat_floodForced": "Flood (afgedwongen)",
"chat_directForced": "Direct (afgedwongen)",
"chat_hopsForced": "{count} hops (afgedwongen)",
"@chat_hopsForced": {
"placeholders": {
"count": {
@ -593,7 +593,7 @@
}
}
},
"chat_floodAuto": "Overstroming (auto)",
"chat_floodAuto": "Flood (auto)",
"chat_direct": "Direct",
"chat_poiShared": "Gedeelde POI",
"chat_unread": "Nieuw: {count}",
@ -605,7 +605,7 @@
}
},
"map_title": "Node Map",
"map_noNodesWithLocation": "Geen knopen met locatiegegevens",
"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": {
@ -624,7 +624,7 @@
}
},
"map_chat": "Chat",
"map_repeater": "Herhaling",
"map_repeater": "Repeater",
"map_room": "Ruimte",
"map_sensor": "Sensor",
"map_pinDm": "Verzenden als bericht (DM)",
@ -652,11 +652,11 @@
}
},
"map_connectToShareMarkers": "Verbind met een apparaat om markers te delen",
"map_filterNodes": "Filter Knopen",
"map_nodeTypes": "Node Types",
"map_chatNodes": "Chat Nodes",
"map_repeaters": "Herhalingen",
"map_otherNodes": "Andere knooppunten",
"map_filterNodes": "Filter Nodes",
"map_nodeTypes": "Nodetypes",
"map_chatNodes": "Chatnodes",
"map_repeaters": "Repeaters",
"map_otherNodes": "Andere Nodes",
"map_keyPrefix": "Prefix sleutel",
"map_filterByKeyPrefix": "Filteren op sleutelvoorgemeld",
"map_publicKeyPrefix": "Openbare sleutelvoorgemeld",
@ -665,7 +665,7 @@
"map_lastSeenTime": "Laatste Bekeken Tijd",
"map_sharedPin": "Gedeelde pin",
"map_joinRoom": "Sluit Kamer",
"map_manageRepeater": "Beheer Herhaling",
"map_manageRepeater": "Beheer Repeater",
"mapCache_title": "Offline Kaarten Cache",
"mapCache_selectAreaFirst": "Select een gebied om eerst in de cache op te slaan",
"mapCache_noTilesToDownload": "Geen tiles te downloaden voor dit gebied.",
@ -788,18 +788,18 @@
"time_allTime": "Alle tijd",
"dialog_disconnect": "Verbinden verbreken",
"dialog_disconnectConfirm": "Ben je er zeker van dat je verbinding met dit apparaat wilt verbreken?",
"login_repeaterLogin": "Herhaalders Inloggen",
"login_repeaterLogin": "Inloggen Repeater",
"login_roomLogin": "Ruimte Inloggen",
"login_password": "Wachtwoord",
"login_enterPassword": "Wachtwoord invoeren",
"login_savePassword": "Wachtwoord opslaan",
"login_savePasswordSubtitle": "Het wachtwoord wordt veilig op dit apparaat opgeslagen.",
"login_repeaterDescription": "Voer het wachtwoord van de herhaling in om instellingen en status te openen.",
"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_routingMode": "Routeerwijze",
"login_autoUseSavedPath": "Automatisch (gebruik opgeslagen pad)",
"login_forceFloodMode": "Dwing Overstromingsmodus",
"login_forceFloodMode": "Dwing Floodmodus Af",
"login_managePaths": "Padbeheer",
"login_login": "Inloggen",
"login_attempt": "Poging {current}/{max}",
@ -821,6 +821,8 @@
}
}
},
"login_failedMessage": "Inloggen mislukt. Het wachtwoord is onjuist of de repeater is niet bereikbaar.",
"common_reload": "Opnieuw laden",
"common_clear": "Schoonmaken",
"path_currentPath": "Huidige pad: {path}",
@ -846,7 +848,7 @@
"path_labelHexPrefixes": "Pad (hex-voorkeursletters)",
"path_helperMaxHops": "Maximaal 64 sprongen. Elke prefix is 2 hexadecimale tekens (1 byte)",
"path_selectFromContacts": "Of select contacten:",
"path_noRepeatersFound": "Geen herhalingen of zaalservers gevonden.",
"path_noRepeatersFound": "Geen repeaters of roomservers gevonden.",
"path_customPathsRequire": "Aangepaste paden vereisen tussentse overstappen die berichten kunnen doorgeven.",
"path_invalidHexPrefixes": "Ongeldige hex-voorkeursletters: {prefixes}",
"@path_invalidHexPrefixes": {
@ -858,20 +860,20 @@
},
"path_tooLong": "Pad is te lang. Maximaal 64 sprongen zijn toegestaan.",
"path_setPath": "Stel Pad in",
"repeater_management": "Beheer Herhalingen",
"repeater_management": "Beheer Repeaters",
"repeater_managementTools": "Beheerinstrumenten",
"repeater_status": "Status",
"repeater_statusSubtitle": "Status, statistieken en buren bekijken",
"repeater_telemetry": "Telemetry",
"repeater_telemetrySubtitle": "Bekijk telemetrie van sensoren en systeemgegevens",
"repeater_cli": "CLI",
"repeater_cliSubtitle": "Verzend commando's naar de herhaaldere",
"repeater_cliSubtitle": "Verzend commando's naar de repeater",
"repeater_settings": "Instellingen",
"repeater_settingsSubtitle": "Configureer repeaterparameters",
"repeater_statusTitle": "Status herhalen",
"repeater_statusTitle": "Status repeater",
"repeater_routingMode": "Routeerwijze",
"repeater_autoUseSavedPath": "Automatisch (gebruik opgeslagen pad)",
"repeater_forceFloodMode": "Dwing Overloopmodus",
"repeater_forceFloodMode": "Dwing Floodmodus Af",
"repeater_pathManagement": "Beheer van paden",
"repeater_refresh": "Vernieuwen",
"repeater_statusRequestTimeout": "Statusverzoek is uitgevallen.",
@ -883,22 +885,22 @@
}
}
},
"repeater_systemInformation": "Systeem Informatie",
"repeater_systemInformation": "Systeeminformatie",
"repeater_battery": "Batterij",
"repeater_clockAtLogin": "Tijd (bij aanmelden)",
"repeater_uptime": "Beschikbaarheid",
"repeater_queueLength": "Wachttijd",
"repeater_debugFlags": "Debug Flags",
"repeater_radioStatistics": "Radio Statistieken",
"repeater_debugFlags": "Debugvlaggen",
"repeater_radioStatistics": "Radiostatistieken",
"repeater_lastRssi": "Laatste RSSI",
"repeater_lastSnr": "Laatste SNR",
"repeater_noiseFloor": "Ruishoordniveau",
"repeater_noiseFloor": "Ruisvloer",
"repeater_txAirtime": "TX Airtime",
"repeater_rxAirtime": "RX Airtime",
"repeater_packetStatistics": "Pakket Statistieken",
"repeater_packetStatistics": "Pakketstatistieken",
"repeater_sent": "Verzonden",
"repeater_received": "Ontvangen",
"repeater_duplicates": "Dubbele",
"repeater_duplicates": "Duplicaat",
"repeater_daysHoursMinsSecs": "{days} dagen {hours} uur {minutes} minuten {seconds} seconden",
"@repeater_daysHoursMinsSecs": {
"placeholders": {
@ -916,7 +918,7 @@
}
}
},
"repeater_packetTxTotal": "Totaal: {total}, Overstroming: {flood}, Direct: {direct}",
"repeater_packetTxTotal": "Totaal: {total}, Flood: {flood}, Direct: {direct}",
"@repeater_packetTxTotal": {
"placeholders": {
"total": {
@ -930,7 +932,7 @@
}
}
},
"repeater_packetRxTotal": "Totaal: {total}, Overstroming: {flood}, Direct: {direct}",
"repeater_packetRxTotal": "Totaal: {total}, Flood: {flood}, Direct: {direct}",
"@repeater_packetRxTotal": {
"placeholders": {
"total": {
@ -944,7 +946,7 @@
}
}
},
"repeater_duplicatesFloodDirect": "Overstroming: {flood}, Direct: {direct}",
"repeater_duplicatesFloodDirect": "Flood: {flood}, Direct: {direct}",
"@repeater_duplicatesFloodDirect": {
"placeholders": {
"flood": {
@ -963,10 +965,10 @@
}
}
},
"repeater_settingsTitle": "Herstelinstellingen",
"repeater_settingsTitle": "Repeater Instellingen",
"repeater_basicSettings": "Basisinstellingen",
"repeater_repeaterName": "Herhaalnaam",
"repeater_repeaterNameHelper": "Weergave naam voor deze herhaling",
"repeater_repeaterName": "Repeaternaam",
"repeater_repeaterNameHelper": "Weergave naam voor deze repeater",
"repeater_adminPassword": "Admin wachtwoord",
"repeater_adminPasswordHelper": "Volledige toegangspaswoord",
"repeater_guestPassword": "Wachtwoord Gast",
@ -977,7 +979,7 @@
"repeater_txPower": "TX Power",
"repeater_txPowerHelper": "1-30 dBm",
"repeater_bandwidth": "Bandbreedte",
"repeater_spreadingFactor": "Spreadsnelheid",
"repeater_spreadingFactor": "Spreidingsfactor",
"repeater_codingRate": "Codeertarief",
"repeater_locationSettings": "Locatie Instellingen",
"repeater_latitude": "Breedtegraad",
@ -985,11 +987,11 @@
"repeater_longitude": "Lengtegraad",
"repeater_longitudeHelper": "Graadseconden (bijv. -122.4194)",
"repeater_features": "Kenmerken",
"repeater_packetForwarding": "Pakketdoorstrooming",
"repeater_packetForwardingSubtitle": "Herstel activeren om pakketten door te sturen",
"repeater_packetForwarding": "Pakketdoorvoering",
"repeater_packetForwardingSubtitle": "Repeater instellen om pakketten door te sturen",
"repeater_guestAccess": "Toegang voor Gasten",
"repeater_guestAccessSubtitle": "Toegestane leesbeheer toegang voor gasten.",
"repeater_privacyMode": "Privacy Mode",
"repeater_privacyMode": "Privacy Modus",
"repeater_privacyModeSubtitle": "Naam/locatie verbergen in advertenties",
"repeater_advertisementSettings": "Advertentie Instellingen",
"repeater_localAdvertInterval": "Lokale Advertentie Interval",
@ -1001,7 +1003,7 @@
}
}
},
"repeater_floodAdvertInterval": "Advertentie Interval bij overstroming",
"repeater_floodAdvertInterval": "Flood Advertentie Interval",
"repeater_floodAdvertIntervalHours": "{hours} uur",
"@repeater_floodAdvertIntervalHours": {
"placeholders": {
@ -1012,15 +1014,15 @@
},
"repeater_encryptedAdvertInterval": "Versleutelde Advertentie Interval",
"repeater_dangerZone": "Gevaarzone",
"repeater_rebootRepeater": "Herstart Herhaalder",
"repeater_rebootRepeaterSubtitle": "De herstart van het herhalerapparaat",
"repeater_rebootRepeater": "Herstart Repeater",
"repeater_rebootRepeaterSubtitle": "Herstart het Repeaterapparaat",
"repeater_rebootRepeaterConfirm": "Ben je er zeker van dat je deze repeater opnieuw wilt opstarten?",
"repeater_regenerateIdentityKey": "Identiteit sleutel opnieuw genereren",
"repeater_regenerateIdentityKeySubtitle": "Nieuwe publieke/private sleutelpaar genereren",
"repeater_regenerateIdentityKeyConfirm": "Dit genereert een nieuwe identiteit voor de herhaling. Doorgaan?",
"repeater_regenerateIdentityKeyConfirm": "Dit genereert een nieuwe identiteit voor de repeater. Doorgaan?",
"repeater_eraseFileSystem": "Verwijder Besturingssysteem",
"repeater_eraseFileSystemSubtitle": "Formateer het herhalende bestandsysteem",
"repeater_eraseFileSystemConfirm": "WAARSCHUWING: Dit zal alle gegevens op de herhaling wissen. Dit kan niet worden teruggedraaid!",
"repeater_eraseFileSystemSubtitle": "Formateer het bestandsysteem van de repeater",
"repeater_eraseFileSystemConfirm": "WAARSCHUWING: Dit zal alle gegevens op de repeater wissen. Dit kan niet worden teruggedraaid!",
"repeater_eraseSerialOnly": "Verwijderen is alleen beschikbaar via de seriële console.",
"repeater_commandSent": "Commando verzonden: {command}",
"@repeater_commandSent": {
@ -1049,7 +1051,7 @@
}
},
"repeater_refreshBasicSettings": "Basisinstellingen vernieuwen",
"repeater_refreshRadioSettings": "Radiozenders Instellingen Bijwerken",
"repeater_refreshRadioSettings": "Radiozender Instellingen Verversen",
"repeater_refreshTxPower": "Nieuw laden TX-vermogen",
"repeater_refreshLocationSettings": "Instellingen Locatie Vernieuwen",
"repeater_refreshPacketForwarding": "Vernieuwen Pakket Doorversturing",
@ -1072,7 +1074,7 @@
}
}
},
"repeater_cliTitle": "Herhaling CLI",
"repeater_cliTitle": "Repeater CLI",
"repeater_debugNextCommand": "Debug Volgende Commando",
"repeater_commandHelp": "Help",
"repeater_clearHistory": "Verwijder Geschiedenis",
@ -1106,14 +1108,14 @@
"repeater_cliHelpClearStats": "Reset verschillende statistiek-tellers naar nul.",
"repeater_cliHelpSetAf": "Stelt de luchtvaartfactor in.",
"repeater_cliHelpSetTx": "Stelt LoRa zendvermogen in dBm. (om te wijzigen)",
"repeater_cliHelpSetRepeat": "Activeert of deactiveert de herhalerrol voor dit knoop.",
"repeater_cliHelpSetRepeat": "Activeert of deactiveert de repeater rol van deze node.",
"repeater_cliHelpSetAllowReadOnly": "(Kamervisie) Als 'aan', dan wordt inloggen met een blanco wachtwoord toegestaan, maar kan niet naar de kamervisie Posten. (alleen lezen mogelijk).",
"repeater_cliHelpSetFloodMax": "Stelt het maximale aantal hops van een inkomend overlastpakket in (indien >= max, wordt het pakket niet doorgestuurd)",
"repeater_cliHelpSetFloodMax": "Stelt het maximale aantal hops van een inkomend floodpakket in (indien >= max, wordt het pakket niet doorgestuurd)",
"repeater_cliHelpSetIntThresh": "Stelt de Interferentiewaarde (in dB) in. Standaardwaarde is 14. Stel in op 0 om het detecteren van kanaalinterferentie uit te schakelen.",
"repeater_cliHelpSetAgcResetInterval": "Stelt het interval in om de Auto Gain Controller te resetten. Stel in op 0 om dit uit te schakelen.",
"repeater_cliHelpSetMultiAcks": "Activeert of deactiveert de functie 'dubbele ACKs'.",
"repeater_cliHelpSetMultiAcks": "Activeert of deactiveert de functie 'duplicate ACKs'.",
"repeater_cliHelpSetAdvertInterval": "Stelt het timerinterval in minuten in om een lokale (zero-hop) advertentiepakket te versturen. Stel in op 0 om uit te schakelen.",
"repeater_cliHelpSetFloodAdvertInterval": "Stelt het timerinterval in uren in om een overstromingsadvertentiepakket te versturen. Stel in op 0 om dit uit te schakelen.",
"repeater_cliHelpSetFloodAdvertInterval": "Stelt het timerinterval in uren in om een floodadvertentiepakket te versturen. Stel in op 0 om dit uit te schakelen.",
"repeater_cliHelpSetGuestPassword": "Stelt/past de gastenwacht aan of wijzigt deze. (voor herstelcontacten kunnen gastelogins de \"Get Stats\" verzoek verzenden)",
"repeater_cliHelpSetName": "Stelt de advertentietitel in.",
"repeater_cliHelpSetLat": "Stelt de breedtegraad van de advertentiekaart in. (graadrijssysteem)",
@ -1136,7 +1138,7 @@
"repeater_cliHelpLogErase": "Verwijdert de pakketlogs uit het bestandssysteem.",
"repeater_cliHelpNeighbors": "Toont een lijst met andere repeater nodes die via nul-hop advertenties zijn gehoord. Elke regel is id-prefix-hex:timestamp:snr-times-4",
"repeater_cliHelpNeighborRemove": "Verwijdert de eerste overeenkomende vermelding (via pubkey prefix (hex)) uit de lijst van buren.",
"repeater_cliHelpRegion": "(reeks alleen) Lijst alle gedefinieerde regio's en huidige overstromingsrechten.",
"repeater_cliHelpRegion": "(Alleen Serieel) Lijst alle gedefinieerde regio's en huidige floodrechten.",
"repeater_cliHelpRegionLoad": "LET OP: dit is een speciale multi-command aanroep. Elke volgende opdracht is een regiortaak (uitgelijnd met spaties om de ouderhiërarchie aan te duiden, met minimaal één spatie). Beëindigd door een lege regel/opdracht te sturen.",
"repeater_cliHelpRegionGet": "Zoekt naar regio met gegeven naam voorvoegsel (of \"\" voor de globale scope). Antwoordt met \"-> regio-naam (ouder-naam) 'F'\"",
"repeater_cliHelpRegionPut": "Voegt of wijzigt een regio-definitie met de gegeven naam.",
@ -1148,8 +1150,8 @@
"repeater_cliHelpRegionSave": "Bewaar de lijst/kaart van de regio's naar de opslag.",
"repeater_cliHelpGps": "Geeft de status van de GPS. Wanneer de GPS uit staat, antwoordt het alleen met \"uit\", als het aan staat, antwoordt het met \"aan\", status, fix, sat count.",
"repeater_cliHelpGpsOnOff": "Schakel de GPS-standby aan/uit.",
"repeater_cliHelpGpsSync": "Synchroniseer knooptime met GPS-klok.",
"repeater_cliHelpGpsSetLoc": "Stel de positie van het knoop vast naar GPS-coördinaten en sla de voorkeuren op.",
"repeater_cliHelpGpsSync": "Synchroniseer node met GPS-klok.",
"repeater_cliHelpGpsSetLoc": "Stel de positie van de node vast als GPS-coördinaten en sla de voorkeuren op.",
"repeater_cliHelpGpsAdvert": "Geeft de locatie advertentieconfiguratie van de node:\n- none: locatie niet in advertenties opnemen\n- share: gps locatie delen (van SensorManager)\n- prefs: locatie adverteren die in de voorkeuren is opgeslagen",
"repeater_cliHelpGpsAdvertSet": "Stelt advertentie locatie configuratie in.",
"repeater_commandsListTitle": "Commandenlijst",
@ -1158,8 +1160,8 @@
"repeater_settingsCategory": "Instellingen",
"repeater_bridge": "Bruggen",
"repeater_logging": "Logging",
"repeater_neighborsRepeaterOnly": "Buren (Alleen herhaald)",
"repeater_regionManagementRepeaterOnly": "Regiobeheer (Alleen voor Repeater)",
"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.",
"repeater_gpsManagement": "Beheer GPS",
"repeater_gpsNote": "De GPS-commando is geïntroduceerd om locatiegerelateerde onderwerpen te beheren.",
@ -1228,12 +1230,12 @@
"channelPath_title": "Pakketpad",
"channelPath_viewMap": "Kaart bekijken",
"channelPath_otherObservedPaths": "Overige Waargenomen Paden",
"channelPath_repeaterHops": "Herhalingstapjes",
"channelPath_repeaterHops": "Repeater Hops",
"channelPath_noHopDetails": "De details van de pakket zijn niet verstrekt.",
"channelPath_messageDetails": "Details Bericht",
"channelPath_senderLabel": "Afzender",
"channelPath_timeLabel": "Tijd",
"channelPath_repeatsLabel": "Herhalen",
"channelPath_repeatsLabel": "Repeats",
"channelPath_pathLabel": "Pad {index}",
"channelPath_observedLabel": "Waargenomen",
"channelPath_observedPathTitle": "Waargenomen pad {index} • {hops}",
@ -1271,7 +1273,7 @@
}
},
"channelPath_unknownPath": "Onbekend",
"channelPath_floodPath": "Overstroming",
"channelPath_floodPath": "Flood",
"channelPath_directPath": "Direct",
"channelPath_observedZeroOf": "0 van {total} sprongen",
"@channelPath_observedZeroOf": {
@ -1293,7 +1295,7 @@
}
},
"channelPath_mapTitle": "Padkaart",
"channelPath_noRepeaterLocations": "Geen herhaler locaties beschikbaar voor deze route.",
"channelPath_noRepeaterLocations": "Geen repeaters beschikbaar voor deze route.",
"channelPath_primaryPath": "Pad {index} (Hoofdtype)",
"@channelPath_primaryPath": {
"placeholders": {
@ -1323,7 +1325,7 @@
}
},
"channelPath_noHopDetailsAvailable": "Geen details beschikbaar voor dit pakket.",
"channelPath_unknownRepeater": "Onbekend Herhaalaar",
"channelPath_unknownRepeater": "Onbekend Repeater",
"listFilter_tooltip": "Filteren en sorteren",
"listFilter_sortBy": "Sorteren door",
"listFilter_latestMessages": "Recente berichten",
@ -1332,10 +1334,11 @@
"listFilter_filters": "Filters",
"listFilter_all": "Alles",
"listFilter_users": "Gebruikers",
"listFilter_repeaters": "Herhalingen",
"listFilter_roomServers": "Kamervirtualisatie",
"listFilter_repeaters": "Repeaters",
"listFilter_roomServers": "Roomservers",
"listFilter_unreadOnly": "Alleen ongelezen",
"listFilter_newGroup": "Nieuwe groep",
"@neighbors_errorLoading": {
"placeholders": {
"error": {
@ -1349,5 +1352,18 @@
"neighbors_RequestTimedOut": "Buren vragen om tijdelijk uitgeschakeld.",
"neighbors_errorLoading": "Fout bij het laden van buren: {error}",
"neighbors_repeatersNeighbours": "Herhalingen Buren",
"neighbors_noData": "Geen gegevens van buren beschikbaar."
"neighbors_noData": "Geen gegevens van buren beschikbaar.",
"channels_createPrivateChannelDesc": "Beveiligd met een geheime sleutel.",
"channels_createPrivateChannel": "Maak een Privé Kanaal",
"channels_joinPrivateChannel": "Sluit een Privé Kanaal aan",
"channels_joinPrivateChannelDesc": "Handmatig een geheime sleutel invoeren.",
"channels_joinPublicChannel": "Sluit het Open Kanaal",
"channels_joinPublicChannelDesc": "Iedereen kan dit kanaal aanmelden.",
"channels_joinHashtagChannel": "Sluit een Hashtag Kanaal",
"channels_joinHashtagChannelDesc": "Iedereen kan lid worden van hashtag-kanalen.",
"channels_scanQrCode": "Scan een QR-code",
"channels_scanQrCodeComingSoon": "Komt later",
"channels_enterHashtag": "Voer hashtag in",
"channels_hashtagHint": "bijv. #team"
}

View file

@ -821,6 +821,8 @@
}
}
},
"login_failedMessage": "Logowanie nie powiodło się. Hasło jest nieprawidłowe albo repeater jest nieosiągalny.",
"common_reload": "Ponownie załadować",
"common_clear": "Wyczyść",
"path_currentPath": "Aktualny ścieżka: {path}",
@ -1336,6 +1338,7 @@
"listFilter_roomServers": "Serwery pokoju",
"listFilter_unreadOnly": "Tylko nieprzeczytane",
"listFilter_newGroup": "Nowa grupa",
"@neighbors_errorLoading": {
"placeholders": {
"error": {
@ -1349,5 +1352,18 @@
"neighbors_RequestTimedOut": "Sąsiedzi proszą o wyłączenie timingu.",
"neighbors_errorLoading": "Błąd podczas ładowania sąsiadów: {error}",
"neighbors_repeatersNeighbours": "Powtarzacze Sąsiedzi",
"neighbors_noData": "Brak danych dotyczących sąsiadów."
"neighbors_noData": "Brak danych dotyczących sąsiadów.",
"channels_joinPrivateChannelDesc": "Ręcznie wprowadź klucz tajny.",
"channels_createPrivateChannel": "Utwórz Prywatny Kanał",
"channels_createPrivateChannelDesc": "Zabezpieczone kluczem szyfrowym.",
"channels_joinPrivateChannel": "Dołącz do Prywatnego Kanału",
"channels_joinPublicChannel": "Dołącz do kanału publicznego.",
"channels_joinPublicChannelDesc": "Każdy może dołączyć do tego kanału.",
"channels_joinHashtagChannel": "Dołącz do kanału oznaczanego hashtagiem",
"channels_joinHashtagChannelDesc": "Każdy może dołączyć do kanałów z hashtagami.",
"channels_scanQrCode": "Skanuj kod QR",
"channels_scanQrCodeComingSoon": "Wkrótce",
"channels_enterHashtag": "Wprowadź hashtag",
"channels_hashtagHint": "np. #zespół"
}

View file

@ -821,6 +821,8 @@
}
}
},
"login_failedMessage": "Falha no login. A senha está incorreta ou o repetidor está inacessível.",
"common_reload": "Recarregar",
"common_clear": "Limpar",
"path_currentPath": "Caminho atual: {path}",
@ -1336,6 +1338,7 @@
"listFilter_roomServers": "Servidores de sala",
"listFilter_unreadOnly": "Apenas não lido",
"listFilter_newGroup": "Novo grupo",
"@neighbors_errorLoading": {
"placeholders": {
"error": {
@ -1349,5 +1352,18 @@
"neighbors_RequestTimedOut": "Vizinhos solicitam tempo limite esgotado.",
"neighbors_errorLoading": "Erro ao carregar vizinhos: {error}",
"neighbors_repeatersNeighbours": "Repetidores Vizinhos",
"neighbors_noData": "Não estão disponíveis dados de vizinhos."
"neighbors_noData": "Não estão disponíveis dados de vizinhos.",
"channels_createPrivateChannelDesc": "Protegido com uma chave secreta.",
"channels_joinPrivateChannelDesc": "Inserir uma chave secreta manualmente.",
"channels_createPrivateChannel": "Criar um Canal Privado",
"channels_joinPrivateChannel": "Junte-se a um Canal Privado",
"channels_joinPublicChannel": "Junte-se ao Canal Público",
"channels_joinPublicChannelDesc": "Qualquer pessoa pode entrar neste canal.",
"channels_joinHashtagChannel": "Junte-se a um Canal com Hashtag",
"channels_joinHashtagChannelDesc": "Qualquer pessoa pode participar de canais com hashtag.",
"channels_scanQrCode": "Digitalizar um Código QR",
"channels_scanQrCodeComingSoon": "Em breve",
"channels_enterHashtag": "Insira hashtag",
"channels_hashtagHint": "ex. #equipe"
}

View file

@ -821,6 +821,8 @@
}
}
},
"login_failedMessage": "Prihlásenie zlyhalo. Heslo je nesprávne alebo je opakovač nedostupný.",
"common_reload": "Načítať",
"common_clear": "Zmazať",
"path_currentPath": "Aktívna cesta: {path}",
@ -1336,6 +1338,7 @@
"listFilter_roomServers": "Servéry miestnosti",
"listFilter_unreadOnly": "Nezaregistrované len",
"listFilter_newGroup": "Nová skupina",
"@neighbors_errorLoading": {
"placeholders": {
"error": {
@ -1349,5 +1352,18 @@
"repeater_neighbours": "Súsezný",
"neighbors_errorLoading": "Chyba pri načítaní susedov: {error}",
"neighbors_repeatersNeighbours": "Opakovadlá Súsezná",
"neighbors_noData": "Nie je dostupná žiadna informácia o susedoch."
"neighbors_noData": "Nie je dostupná žiadna informácia o susedoch.",
"channels_createPrivateChannel": "Vytvorte súkromný kanál",
"channels_joinPrivateChannel": "Pripojiť sa k súkromnému kanálu",
"channels_joinPrivateChannelDesc": "Ručne zadajte tajný kľúč.",
"channels_createPrivateChannelDesc": "Zabezpečené pomocou tajného kľúča.",
"channels_joinPublicChannel": "Pripojte sa k verejnému kanálu",
"channels_joinPublicChannelDesc": "Któvek sátó na tutó kanalizovát.",
"channels_joinHashtagChannel": "Pripojte sa k Hashtag Kanálu",
"channels_joinHashtagChannelDesc": "Ktoekolikoľvek sa môže pridať do hashtag kanálov.",
"channels_scanQrCode": "Skenujte QR kód",
"channels_scanQrCodeComingSoon": "Čoskoro",
"channels_enterHashtag": "Zadajte hashtag",
"channels_hashtagHint": "napr. #tím"
}

View file

@ -821,6 +821,8 @@
}
}
},
"login_failedMessage": "Prijava je bila neuspešna. Geslo je napačno ali pa je repetitor nedosegljiv.",
"common_reload": "Ponovno naloži",
"common_clear": "Ponoviti",
"path_currentPath": "Trenutna pot: {path}",
@ -1336,6 +1338,7 @@
"listFilter_roomServers": "Smeti za prostore",
"listFilter_unreadOnly": "Nezbrani samo",
"listFilter_newGroup": "Nova skupina",
"@neighbors_errorLoading": {
"placeholders": {
"error": {
@ -1349,5 +1352,18 @@
"neighbors_RequestTimedOut": "Sosedi zahtevajo izklop po dogovoru.",
"neighbors_errorLoading": "Napaka pri obnašanju sosedov: {error}",
"neighbors_repeatersNeighbours": "Ponovitve Sosedi",
"neighbors_noData": "Niso na voljo podatki o sosedih."
"neighbors_noData": "Niso na voljo podatki o sosedih.",
"channels_joinPrivateChannel": "Pridružite se zasebni skupini",
"channels_createPrivateChannelDesc": "Varno zaklenjeno s skrivnim ključem.",
"channels_joinPrivateChannelDesc": "Ročno vnesite zaporni ključ.",
"channels_createPrivateChannel": "Ustvari zasebno kanal.",
"channels_joinPublicChannel": "Pridružite se javnemu kanalu",
"channels_joinPublicChannelDesc": "Kdor karkoli je, lahko se pridruži tej skupini.",
"channels_joinHashtagChannel": "Pridružite se Kanalu z Hashtagom",
"channels_joinHashtagChannelDesc": "Kdor karkoli, lahko se pridruži hashtag kanalom.",
"channels_scanQrCode": "Skeniraj QR kodo",
"channels_scanQrCodeComingSoon": "Prihajajoča",
"channels_enterHashtag": "Vnesite hashtag",
"channels_hashtagHint": "npr. #ekipa"
}

View file

@ -821,6 +821,8 @@
}
}
},
"login_failedMessage": "Inloggning misslyckades. Antingen är lösenordet fel eller så går det inte att nå repeatern.",
"common_reload": "Ladda om",
"common_clear": "Rensa",
"path_currentPath": "Nuvarande sökväg: {path}",
@ -1336,6 +1338,7 @@
"listFilter_roomServers": "Rumservrar",
"listFilter_unreadOnly": "Endast oinlästa",
"listFilter_newGroup": "Ny grupp",
"@neighbors_errorLoading": {
"placeholders": {
"error": {
@ -1349,5 +1352,18 @@
"neighbors_RequestTimedOut": "Grannar begär tidsinställd utskick.",
"neighbors_errorLoading": "Fel vid inläsning av grannar: {error}",
"neighbors_repeatersNeighbours": "Upprepar grannar",
"neighbors_noData": "Inga grannuppgifter finns tillgängliga."
"neighbors_noData": "Inga grannuppgifter finns tillgängliga.",
"channels_createPrivateChannel": "Skapa en privat kanal",
"channels_joinPrivateChannel": "Gå med i en Privat Kanal",
"channels_joinPrivateChannelDesc": "Ange en hemlig nyckel manuellt.",
"channels_createPrivateChannelDesc": "Skyddat med en hemlig nyckel.",
"channels_joinPublicChannel": "Gå med i den Offentliga Kanalen",
"channels_joinPublicChannelDesc": "Vem som helst kan gå med i denna kanal.",
"channels_joinHashtagChannel": "Gå med i en Hashtagkanal",
"channels_joinHashtagChannelDesc": "Väldigt enkelt att gå med i hashtag-kanaler.",
"channels_scanQrCode": "Skanna en QR-kod",
"channels_scanQrCodeComingSoon": "Kommer snart",
"channels_enterHashtag": "Ange hashtag",
"channels_hashtagHint": "t.ex. #team"
}

View file

@ -821,6 +821,8 @@
}
}
},
"login_failedMessage": "登录失败。密码不正确或中继器不可达。",
"common_reload": "重新加载",
"common_clear": "清除",
"path_currentPath": "当前路径:{path}",
@ -1336,6 +1338,7 @@
"listFilter_roomServers": "房间服务器",
"listFilter_unreadOnly": "未读消息",
"listFilter_newGroup": "新组",
"@neighbors_errorLoading": {
"placeholders": {
"error": {
@ -1349,5 +1352,18 @@
"neighbors_RequestTimedOut": "邻居请求超时处理。",
"neighbors_errorLoading": "加载邻居时出错:{error}",
"neighbors_repeatersNeighbours": "重复器邻居",
"neighbors_noData": "没有可用的邻居数据。"
"neighbors_noData": "没有可用的邻居数据。",
"channels_joinPrivateChannel": "加入私密频道",
"channels_createPrivateChannelDesc": "使用密钥保护。",
"channels_joinPrivateChannelDesc": "手动输入密钥。",
"channels_createPrivateChannel": "创建私聊频道",
"channels_joinPublicChannel": "加入公共频道",
"channels_joinPublicChannelDesc": "任何人都可以加入这个频道。",
"channels_joinHashtagChannel": "加入标签频道",
"channels_joinHashtagChannelDesc": "任何人都可以加入话题频道。",
"channels_scanQrCode": "扫描二维码",
"channels_scanQrCodeComingSoon": "即将到来",
"channels_enterHashtag": "输入标签",
"channels_hashtagHint": "例如 #团队"
}

View file

@ -27,7 +27,7 @@ void main() async {
final storage = StorageService();
final connector = MeshCoreConnector();
final pathHistoryService = PathHistoryService(storage);
final retryService = MessageRetryService(storage);
final retryService = MessageRetryService();
final appSettingsService = AppSettingsService();
final bleDebugLogService = BleDebugLogService();
final appDebugLogService = AppDebugLogService();

View file

@ -1,5 +1,8 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:crypto/crypto.dart' as crypto;
import '../connector/meshcore_protocol.dart';
class Channel {
@ -61,6 +64,15 @@ class Channel {
return bytes;
}
/// Derive PSK from hashtag name using SHA256.
/// The hashtag is normalized to include '#' prefix.
/// Returns first 16 bytes of SHA256 hash as PSK.
static Uint8List derivePskFromHashtag(String hashtag) {
final name = hashtag.startsWith('#') ? hashtag : '#$hashtag';
final hash = crypto.sha256.convert(utf8.encode(name)).bytes;
return Uint8List.fromList(hash.sublist(0, 16));
}
static String formatPskHex(Uint8List psk) {
return _bytesToHex(psk);
}

View file

@ -515,132 +515,318 @@ class _ChannelsScreenState extends State<ChannelsScreen>
void _showAddChannelDialog(BuildContext context) {
final connector = context.read<MeshCoreConnector>();
final nextIndex = _findNextAvailableIndex(connector.channels, connector.maxChannels);
final hasPublicChannel = connector.channels.any((c) => c.isPublicChannel);
int? selectedOption;
final nameController = TextEditingController();
final pskController = TextEditingController();
final maxChannels = connector.maxChannels;
int selectedIndex = _findNextAvailableIndex(connector.channels, maxChannels);
bool usePublicPsk = false;
final hashtagController = TextEditingController();
showDialog(
context: context,
builder: (dialogContext) => StatefulBuilder(
builder: (dialogContext, setDialogState) => AlertDialog(
title: Text(dialogContext.l10n.channels_addChannel),
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
DropdownButtonFormField<int>(
initialValue: selectedIndex,
decoration: InputDecoration(
labelText: dialogContext.l10n.channels_channelIndexLabel,
border: const OutlineInputBorder(),
),
items: List.generate(maxChannels, (i) => i)
.map((i) => DropdownMenuItem(
value: i,
child: Text(dialogContext.l10n.channels_channelIndex(i)),
))
.toList(),
onChanged: (value) {
if (value != null) {
setDialogState(() => selectedIndex = value);
}
},
builder: (dialogContext, setDialogState) {
Widget buildOptionTile({
required int optionIndex,
required IconData icon,
required String title,
required String subtitle,
bool enabled = true,
}) {
final isSelected = selectedOption == optionIndex;
return ListTile(
leading: CircleAvatar(
backgroundColor: enabled
? (isSelected ? Theme.of(dialogContext).colorScheme.primaryContainer : null)
: Colors.grey.withValues(alpha: 0.2),
child: Icon(
icon,
color: enabled
? (isSelected ? Theme.of(dialogContext).colorScheme.primary : null)
: Colors.grey,
),
const SizedBox(height: 16),
TextField(
controller: nameController,
decoration: InputDecoration(
labelText: dialogContext.l10n.channels_channelName,
border: const OutlineInputBorder(),
),
maxLength: 31,
),
const SizedBox(height: 8),
CheckboxListTile(
title: Text(dialogContext.l10n.channels_usePublicChannel),
subtitle: Text(dialogContext.l10n.channels_standardPublicPsk),
value: usePublicPsk,
onChanged: (value) {
setDialogState(() {
usePublicPsk = value ?? false;
if (usePublicPsk) {
nameController.text = 'Public';
pskController.text = Channel.publicChannelPsk;
} else {
),
title: Text(
title,
style: TextStyle(color: enabled ? null : Colors.grey),
),
subtitle: Text(
subtitle,
style: TextStyle(color: enabled ? null : Colors.grey),
),
trailing: enabled ? const Icon(Icons.chevron_right) : null,
selected: isSelected,
onTap: enabled
? () {
setDialogState(() {
selectedOption = optionIndex;
nameController.clear();
pskController.clear();
}
});
},
),
if (!usePublicPsk) ...[
const SizedBox(height: 8),
TextField(
controller: pskController,
decoration: InputDecoration(
labelText: dialogContext.l10n.channels_pskHex,
border: const OutlineInputBorder(),
suffixIcon: IconButton(
icon: const Icon(Icons.casino),
tooltip: dialogContext.l10n.channels_generateRandomPsk,
onPressed: () {
final random = Random.secure();
final bytes = Uint8List(16);
for (int i = 0; i < 16; i++) {
bytes[i] = random.nextInt(256);
}
pskController.text = Channel.formatPskHex(bytes);
},
hashtagController.clear();
});
}
: null,
);
}
Widget? buildExpandedContent() {
switch (selectedOption) {
case 0: // Create Private Channel
return Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: TextField(
controller: nameController,
decoration: InputDecoration(
labelText: dialogContext.l10n.channels_channelName,
border: const OutlineInputBorder(),
),
maxLength: 31,
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Row(
children: [
Expanded(
child: FilledButton(
onPressed: () {
final name = nameController.text.trim();
if (name.isEmpty) {
ScaffoldMessenger.of(dialogContext).showSnackBar(
SnackBar(content: Text(dialogContext.l10n.channels_enterChannelName)),
);
return;
}
final random = Random.secure();
final psk = Uint8List(16);
for (int i = 0; i < 16; i++) {
psk[i] = random.nextInt(256);
}
Navigator.pop(dialogContext);
connector.setChannel(nextIndex, name, psk);
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(context.l10n.channels_channelAdded(name))),
);
}
},
child: Text(dialogContext.l10n.common_create),
),
),
],
),
),
],
);
case 1: // Join Private Channel
return Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: TextField(
controller: nameController,
decoration: InputDecoration(
labelText: dialogContext.l10n.channels_channelName,
border: const OutlineInputBorder(),
),
maxLength: 31,
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: TextField(
controller: pskController,
decoration: InputDecoration(
labelText: dialogContext.l10n.channels_pskHex,
border: const OutlineInputBorder(),
),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Row(
children: [
Expanded(
child: FilledButton(
onPressed: () {
final name = nameController.text.trim();
final pskHex = pskController.text.trim();
if (name.isEmpty) {
ScaffoldMessenger.of(dialogContext).showSnackBar(
SnackBar(content: Text(dialogContext.l10n.channels_enterChannelName)),
);
return;
}
Uint8List psk;
try {
psk = Channel.parsePskHex(pskHex);
} on FormatException {
ScaffoldMessenger.of(dialogContext).showSnackBar(
SnackBar(content: Text(dialogContext.l10n.channels_pskMustBe32Hex)),
);
return;
}
Navigator.pop(dialogContext);
connector.setChannel(nextIndex, name, psk);
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(context.l10n.channels_channelAdded(name))),
);
}
},
child: Text(dialogContext.l10n.common_add),
),
),
],
),
),
],
);
case 2: // Join Public Channel
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Row(
children: [
Expanded(
child: FilledButton(
onPressed: () {
final psk = Channel.parsePskHex(Channel.publicChannelPsk);
Navigator.pop(dialogContext);
connector.setChannel(nextIndex, 'Public', psk);
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(context.l10n.channels_publicChannelAdded)),
);
}
},
child: Text(dialogContext.l10n.common_add),
),
),
],
),
],
],
),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(dialogContext),
child: Text(dialogContext.l10n.common_cancel),
),
FilledButton(
onPressed: () {
final name = nameController.text.trim();
final pskHex = usePublicPsk
? Channel.publicChannelPsk
: pskController.text.trim();
);
if (name.isEmpty) {
ScaffoldMessenger.of(dialogContext).showSnackBar(
SnackBar(content: Text(dialogContext.l10n.channels_enterChannelName)),
);
return;
}
case 3: // Join Hashtag Channel
return Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: TextField(
controller: hashtagController,
decoration: InputDecoration(
labelText: dialogContext.l10n.channels_enterHashtag,
hintText: dialogContext.l10n.channels_hashtagHint,
border: const OutlineInputBorder(),
prefixIcon: const Icon(Icons.tag),
),
maxLength: 31,
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Row(
children: [
Expanded(
child: FilledButton(
onPressed: () {
var hashtag = hashtagController.text.trim();
if (hashtag.isEmpty) {
ScaffoldMessenger.of(dialogContext).showSnackBar(
SnackBar(content: Text(dialogContext.l10n.channels_enterChannelName)),
);
return;
}
// Normalize hashtag name
final name = hashtag.startsWith('#') ? hashtag : '#$hashtag';
final psk = Channel.derivePskFromHashtag(hashtag);
Navigator.pop(dialogContext);
connector.setChannel(nextIndex, name, psk);
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(context.l10n.channels_channelAdded(name))),
);
}
},
child: Text(dialogContext.l10n.common_add),
),
),
],
),
),
],
);
Uint8List psk;
try {
psk = Channel.parsePskHex(pskHex);
} on FormatException {
ScaffoldMessenger.of(dialogContext).showSnackBar(
SnackBar(content: Text(dialogContext.l10n.channels_pskMustBe32Hex)),
);
return;
}
default:
return null;
}
}
Navigator.pop(dialogContext);
connector.setChannel(selectedIndex, name, psk);
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(context.l10n.channels_channelAdded(name))),
);
}
},
child: Text(dialogContext.l10n.common_add),
return AlertDialog(
title: Text(dialogContext.l10n.channels_addChannel),
contentPadding: const EdgeInsets.symmetric(vertical: 16),
content: SizedBox(
width: double.maxFinite,
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
buildOptionTile(
optionIndex: 0,
icon: Icons.add,
title: dialogContext.l10n.channels_createPrivateChannel,
subtitle: dialogContext.l10n.channels_createPrivateChannelDesc,
),
if (selectedOption == 0) buildExpandedContent()!,
const Divider(height: 1),
buildOptionTile(
optionIndex: 1,
icon: Icons.lock,
title: dialogContext.l10n.channels_joinPrivateChannel,
subtitle: dialogContext.l10n.channels_joinPrivateChannelDesc,
),
if (selectedOption == 1) buildExpandedContent()!,
if (!hasPublicChannel) ...[
const Divider(height: 1),
buildOptionTile(
optionIndex: 2,
icon: Icons.public,
title: dialogContext.l10n.channels_joinPublicChannel,
subtitle: dialogContext.l10n.channels_joinPublicChannelDesc,
),
if (selectedOption == 2) buildExpandedContent()!,
],
const Divider(height: 1),
buildOptionTile(
optionIndex: 3,
icon: Icons.tag,
title: dialogContext.l10n.channels_joinHashtagChannel,
subtitle: dialogContext.l10n.channels_joinHashtagChannelDesc,
),
if (selectedOption == 3) buildExpandedContent()!,
const Divider(height: 1),
buildOptionTile(
optionIndex: 4,
icon: Icons.qr_code,
title: dialogContext.l10n.channels_scanQrCode,
subtitle: dialogContext.l10n.channels_scanQrCodeComingSoon,
enabled: false,
),
],
),
),
),
],
),
actions: [
TextButton(
onPressed: () => Navigator.pop(dialogContext),
child: Text(dialogContext.l10n.common_close),
),
],
);
},
),
);
}

View file

@ -759,13 +759,14 @@ class _ContactTile extends StatelessWidget {
@override
Widget build(BuildContext context) {
final shotPublicKey = "<${contact.publicKeyHex.substring(0, 8)}...${contact.publicKeyHex.substring(contact.publicKeyHex.length - 8)}>";
return ListTile(
leading: CircleAvatar(
backgroundColor: _getTypeColor(contact.type),
child: _buildContactAvatar(contact),
),
title: Text(contact.name),
subtitle: Text('${contact.typeLabel}${contact.pathLabel}'),
subtitle: Text('${contact.typeLabel}${contact.pathLabel} $shotPublicKey'),
trailing: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,

View file

@ -1,3 +1,5 @@
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart';
@ -47,6 +49,8 @@ class _MapScreenState extends State<MapScreen> {
final Set<String> _hiddenMarkerIds = {};
Set<String> _removedMarkerIds = {};
bool _isSelectingPoi = false;
bool _hasInitializedMap = false;
bool _removedMarkersLoaded = false;
@override
void initState() {
@ -67,9 +71,39 @@ class _MapScreenState extends State<MapScreen> {
if (!mounted) return;
setState(() {
_removedMarkerIds = ids;
_removedMarkersLoaded = true;
});
}
double _standardDeviation(List<double> values) {
if (values.length <= 1) {
return 0.0;
}
final mean = values.reduce((a, b) => a + b) / values.length;
double sumSquaredDiff = 0.0;
for (final value in values) {
final diff = value - mean;
sumSquaredDiff += diff * diff;
}
// Sample standard deviation (n-1) most appropriate here
final variance = sumSquaredDiff / (values.length - 1);
return sqrt(variance);
}
// Calculate zoom level based on the spread of points (std deviation in degrees)
double _zoomFromStdDev(double latStdDev, double lonStdDev) {
final maxSpread = max(latStdDev, lonStdDev);
if (maxSpread <= 0) return 13.0;
// Approzimate: each zoom level halves the visible area
// ~0.01 degrees spread -> zoom 13, ~0.1 -> zoom 10, ~1.0 -> zoom 7
final zoom = 10.0 - log(maxSpread * 10 + 1) / ln10 * 3;
return zoom.clamp(4.0, 15.0);
}
@override
Widget build(BuildContext context) {
return Consumer2<MeshCoreConnector, AppSettingsService>(
@ -80,10 +114,12 @@ class _MapScreenState extends State<MapScreen> {
final highlightPosition = widget.highlightPosition;
final sharedMarkers = settings.mapShowMarkers
? _collectSharedMarkers(connector)
.where((marker) =>
!_hiddenMarkerIds.contains(marker.id) &&
!_removedMarkerIds.contains(marker.id))
.toList()
.where(
(marker) =>
!_hiddenMarkerIds.contains(marker.id) &&
!_removedMarkerIds.contains(marker.id),
)
.toList()
: <_SharedMarker>[];
// Filter by time
@ -91,16 +127,18 @@ class _MapScreenState extends State<MapScreen> {
final filteredByTime = settings.mapTimeFilterHours == 0
? contacts
: contacts.where((c) {
final hoursSinceLastSeen =
now.difference(c.lastSeen).inHours;
final hoursSinceLastSeen = now.difference(c.lastSeen).inHours;
return hoursSinceLastSeen <= settings.mapTimeFilterHours;
}).toList();
// Filter by key prefix
final keyPrefix = settings.mapKeyPrefix.trim();
final filteredByKeyPrefix = (settings.mapKeyPrefixEnabled && keyPrefix.isNotEmpty)
final filteredByKeyPrefix =
(settings.mapKeyPrefixEnabled && keyPrefix.isNotEmpty)
? filteredByTime.where((c) {
return c.publicKeyHex.toLowerCase().startsWith(keyPrefix.toLowerCase());
return c.publicKeyHex.toLowerCase().startsWith(
keyPrefix.toLowerCase(),
);
}).toList()
: filteredByTime;
@ -109,30 +147,91 @@ class _MapScreenState extends State<MapScreen> {
.where((c) => c.hasLocation)
.toList();
// Calculate center of all nodes, or default to (0, 0)
// Calculate center and zoom of all nodes, or default to (0, 0)
LatLng center = const LatLng(0, 0);
final hasMapContent = contactsWithLocation.isNotEmpty ||
double initialZoom = 10.0;
final hasMapContent =
contactsWithLocation.isNotEmpty ||
sharedMarkers.isNotEmpty ||
_isSelectingPoi ||
highlightPosition != null;
if (contactsWithLocation.isNotEmpty || sharedMarkers.isNotEmpty) {
double avgLat = contactsWithLocation
.map((c) => c.latitude!)
.fold<double>(0, (sum, lat) => sum + lat);
double avgLon = contactsWithLocation
.map((c) => c.longitude!)
.fold<double>(0, (sum, lon) => sum + lon);
for (final marker in sharedMarkers) {
avgLat += marker.position.latitude;
avgLon += marker.position.longitude;
}
final total = contactsWithLocation.length + sharedMarkers.length;
if (total > 0) {
center = LatLng(avgLat / total, avgLon / total);
final allPoints = [
...contactsWithLocation.map(
(c) => LatLng(c.latitude!, c.longitude!),
),
...sharedMarkers.map((m) => m.position),
];
if (allPoints.length >= 3) {
final latValues = allPoints.map((p) => p.latitude).toList();
final lonValues = allPoints.map((p) => p.longitude).toList();
final meanLat =
latValues.reduce((a, b) => a + b) / latValues.length;
final meanLon =
lonValues.reduce((a, b) => a + b) / lonValues.length;
final latStdDev = _standardDeviation(latValues);
final lonStdDev = _standardDeviation(lonValues);
final filteredPoints = allPoints
.where(
(p) =>
(p.latitude - meanLat).abs() <= latStdDev * 2 &&
(p.longitude - meanLon).abs() <= lonStdDev * 2,
)
.toList();
if (filteredPoints.isNotEmpty) {
final filteredLatValues = filteredPoints
.map((p) => p.latitude)
.toList();
final filteredLonValues = filteredPoints
.map((p) => p.longitude)
.toList();
final avgLat = filteredLatValues.reduce((a, b) => a + b);
final avgLon = filteredLonValues.reduce((a, b) => a + b);
center = LatLng(
avgLat / filteredPoints.length,
avgLon / filteredPoints.length,
);
// Use std deviation of filtered points for zoom
final filteredLatStdDev = _standardDeviation(filteredLatValues);
final filteredLonStdDev = _standardDeviation(filteredLonValues);
initialZoom = _zoomFromStdDev(
filteredLatStdDev,
filteredLonStdDev,
);
} else {
center = LatLng(meanLat, meanLon);
initialZoom = _zoomFromStdDev(latStdDev, lonStdDev);
}
} else {
double avgLat = 0.0;
double avgLon = 0.0;
for (final point in allPoints) {
avgLat += point.latitude;
avgLon += point.longitude;
}
center = LatLng(
avgLat / allPoints.length,
avgLon / allPoints.length,
);
initialZoom = 12.0;
}
}
if (highlightPosition != null) {
center = highlightPosition;
initialZoom = widget.highlightZoom;
}
// Re center map after removed markers have loaded
if (!_hasInitializedMap && _removedMarkersLoaded && hasMapContent) {
_hasInitializedMap = true;
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
_mapController.move(center, initialZoom);
}
});
}
final allowBack = !connector.isConnected;
@ -156,7 +255,9 @@ class _MapScreenState extends State<MapScreen> {
tooltip: context.l10n.common_settings,
onPressed: () => Navigator.push(
context,
MaterialPageRoute(builder: (context) => const SettingsScreen()),
MaterialPageRoute(
builder: (context) => const SettingsScreen(),
),
),
),
],
@ -169,7 +270,7 @@ class _MapScreenState extends State<MapScreen> {
mapController: _mapController,
options: MapOptions(
initialCenter: center,
initialZoom: 13.0,
initialZoom: initialZoom,
minZoom: 2.0,
maxZoom: 18.0,
onTap: (_, latLng) {
@ -234,14 +335,18 @@ class _MapScreenState extends State<MapScreen> {
),
],
),
_buildLegend(contactsWithLocation.length, sharedMarkers.length),
_buildLegend(
contactsWithLocation.length,
sharedMarkers.length,
),
],
),
bottomNavigationBar: SafeArea(
top: false,
child: QuickSwitchBar(
selectedIndex: 2,
onDestinationSelected: (index) => _handleQuickSwitch(index, context),
onDestinationSelected: (index) =>
_handleQuickSwitch(index, context),
),
),
floatingActionButton: FloatingActionButton(
@ -259,27 +364,17 @@ class _MapScreenState extends State<MapScreen> {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.location_off,
size: 64,
color: Colors.grey[400],
),
Icon(Icons.location_off, size: 64, color: Colors.grey[400]),
const SizedBox(height: 16),
Text(
context.l10n.map_noNodesWithLocation,
style: TextStyle(
fontSize: 18,
color: Colors.grey[600],
),
style: TextStyle(fontSize: 18, color: Colors.grey[600]),
),
const SizedBox(height: 8),
Text(
context.l10n.map_nodesNeedGps,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14,
color: Colors.grey[500],
),
style: TextStyle(fontSize: 14, color: Colors.grey[500]),
),
],
),
@ -293,7 +388,9 @@ class _MapScreenState extends State<MapScreen> {
if (!contact.hasLocation) continue;
// Apply node type filters
if (contact.type == advTypeRepeater && !settings.mapShowRepeaters) continue;
if (contact.type == advTypeRepeater && !settings.mapShowRepeaters) {
continue;
}
if (contact.type == advTypeChat && !settings.mapShowChatNodes) continue;
if (contact.type != advTypeChat &&
contact.type != advTypeRepeater &&
@ -396,13 +493,37 @@ class _MapScreenState extends State<MapScreen> {
),
),
const SizedBox(height: 8),
_buildLegendItem(Icons.person, context.l10n.map_chat, Colors.blue),
_buildLegendItem(Icons.router, context.l10n.map_repeater, Colors.green),
_buildLegendItem(Icons.meeting_room, context.l10n.map_room, Colors.purple),
_buildLegendItem(Icons.sensors, context.l10n.map_sensor, Colors.orange),
_buildLegendItem(
Icons.person,
context.l10n.map_chat,
Colors.blue,
),
_buildLegendItem(
Icons.router,
context.l10n.map_repeater,
Colors.green,
),
_buildLegendItem(
Icons.meeting_room,
context.l10n.map_room,
Colors.purple,
),
_buildLegendItem(
Icons.sensors,
context.l10n.map_sensor,
Colors.orange,
),
_buildLegendItem(Icons.flag, context.l10n.map_pinDm, Colors.blue),
_buildLegendItem(Icons.flag, context.l10n.map_pinPrivate, Colors.purple),
_buildLegendItem(Icons.flag, context.l10n.map_pinPublic, Colors.orange),
_buildLegendItem(
Icons.flag,
context.l10n.map_pinPrivate,
Colors.purple,
),
_buildLegendItem(
Icons.flag,
context.l10n.map_pinPublic,
Colors.orange,
),
],
),
),
@ -418,10 +539,7 @@ class _MapScreenState extends State<MapScreen> {
children: [
Icon(icon, size: 16, color: color),
const SizedBox(width: 8),
Text(
label,
style: const TextStyle(fontSize: 12),
),
Text(label, style: const TextStyle(fontSize: 12)),
],
),
);
@ -475,7 +593,9 @@ class _MapScreenState extends State<MapScreen> {
label: payload.label,
flags: payload.flags,
fromName: message.senderName,
sourceLabel: channel.name.isEmpty ? 'Channel ${channel.index}' : channel.name,
sourceLabel: channel.name.isEmpty
? 'Channel ${channel.index}'
: channel.name,
isChannel: true,
isPublicChannel: isPublic,
),
@ -541,11 +661,7 @@ class _MapScreenState extends State<MapScreen> {
),
],
),
child: const Icon(
Icons.flag,
color: Colors.white,
size: 20,
),
child: const Icon(Icons.flag, color: Colors.white, size: 20),
),
],
),
@ -563,10 +679,8 @@ class _MapScreenState extends State<MapScreen> {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => RepeaterHubScreen(
repeater: repeater,
password: password,
),
builder: (context) =>
RepeaterHubScreen(repeater: repeater, password: password),
),
);
},
@ -584,9 +698,7 @@ class _MapScreenState extends State<MapScreen> {
context.read<MeshCoreConnector>().markContactRead(room.publicKeyHex);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ChatScreen(contact: room),
),
MaterialPageRoute(builder: (context) => ChatScreen(contact: room)),
);
},
),
@ -613,9 +725,14 @@ class _MapScreenState extends State<MapScreen> {
children: [
_buildInfoRow('Type', contact.typeLabel),
_buildInfoRow('Path', contact.pathLabel),
_buildInfoRow('Location',
'${contact.latitude!.toStringAsFixed(6)}, ${contact.longitude!.toStringAsFixed(6)}'),
_buildInfoRow(context.l10n.map_lastSeen, _formatLastSeen(contact.lastSeen)),
_buildInfoRow(
'Location',
'${contact.latitude!.toStringAsFixed(6)}, ${contact.longitude!.toStringAsFixed(6)}',
),
_buildInfoRow(
context.l10n.map_lastSeen,
_formatLastSeen(contact.lastSeen),
),
_buildInfoRow('Public Key', contact.publicKeyHex),
],
),
@ -624,7 +741,8 @@ class _MapScreenState extends State<MapScreen> {
onPressed: () => Navigator.pop(dialogContext),
child: Text(context.l10n.common_close),
),
if (contact.type == advTypeChat) // Only show chat button for chat nodes
if (contact.type ==
advTypeChat) // Only show chat button for chat nodes
TextButton(
onPressed: () {
Navigator.pop(dialogContext);
@ -637,22 +755,22 @@ class _MapScreenState extends State<MapScreen> {
},
child: Text(context.l10n.contacts_openChat),
),
if (contact.type == advTypeRepeater)
TextButton(
onPressed: () {
Navigator.pop(dialogContext);
_showRepeaterLogin(context, contact);
},
child: Text(context.l10n.map_manageRepeater),
),
if (contact.type == advTypeRoom)
TextButton(
onPressed: () {
Navigator.pop(dialogContext);
_showRoomLogin(context, contact);
},
child: Text(context.l10n.map_joinRoom),
),
if (contact.type == advTypeRepeater)
TextButton(
onPressed: () {
Navigator.pop(dialogContext);
_showRepeaterLogin(context, contact);
},
child: Text(context.l10n.map_manageRepeater),
),
if (contact.type == advTypeRoom)
TextButton(
onPressed: () {
Navigator.pop(dialogContext);
_showRoomLogin(context, contact);
},
child: Text(context.l10n.map_joinRoom),
),
],
),
);
@ -664,17 +782,13 @@ class _MapScreenState extends State<MapScreen> {
case 0:
Navigator.pushReplacement(
context,
buildQuickSwitchRoute(
const ContactsScreen(hideBackButton: true),
),
buildQuickSwitchRoute(const ContactsScreen(hideBackButton: true)),
);
break;
case 1:
Navigator.pushReplacement(
context,
buildQuickSwitchRoute(
const ChannelsScreen(hideBackButton: true),
),
buildQuickSwitchRoute(const ChannelsScreen(hideBackButton: true)),
);
break;
}
@ -722,7 +836,8 @@ class _MapScreenState extends State<MapScreen> {
'Location',
'${marker.position.latitude.toStringAsFixed(6)}, ${marker.position.longitude.toStringAsFixed(6)}',
),
if (marker.flags.isNotEmpty) _buildInfoRow(context.l10n.map_flags, marker.flags),
if (marker.flags.isNotEmpty)
_buildInfoRow(context.l10n.map_flags, marker.flags),
],
),
actions: [
@ -772,10 +887,7 @@ class _MapScreenState extends State<MapScreen> {
),
),
const SizedBox(height: 2),
Text(
value,
style: const TextStyle(fontSize: 14),
),
Text(value, style: const TextStyle(fontSize: 14)),
],
),
);
@ -860,7 +972,10 @@ class _MapScreenState extends State<MapScreen> {
);
}
Future<String?> _promptForLabel(BuildContext context, String defaultLabel) async {
Future<String?> _promptForLabel(
BuildContext context,
String defaultLabel,
) async {
final controller = TextEditingController(text: defaultLabel);
return showDialog<String>(
context: context,
@ -881,7 +996,10 @@ class _MapScreenState extends State<MapScreen> {
TextButton(
onPressed: () {
final label = controller.text.trim().replaceAll('|', '/');
Navigator.pop(dialogContext, label.isEmpty ? defaultLabel : label);
Navigator.pop(
dialogContext,
label.isEmpty ? defaultLabel : label,
);
},
child: Text(context.l10n.common_continue),
),
@ -913,8 +1031,11 @@ class _MapScreenState extends State<MapScreen> {
return Consumer<MeshCoreConnector>(
builder: (consumerContext, liveConnector, child) {
final allContacts = liveConnector.contacts
.where((contact) =>
contact.type != advTypeRepeater && contact.type != advTypeRoom)
.where(
(contact) =>
contact.type != advTypeRepeater &&
contact.type != advTypeRoom,
)
.toList();
return SafeArea(
child: SingleChildScrollView(
@ -924,7 +1045,10 @@ class _MapScreenState extends State<MapScreen> {
children: [
Padding(
padding: const EdgeInsets.fromLTRB(16, 12, 16, 4),
child: Text(context.l10n.map_sendToContact, style: const TextStyle(fontWeight: FontWeight.bold)),
child: Text(
context.l10n.map_sendToContact,
style: const TextStyle(fontWeight: FontWeight.bold),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(16, 4, 16, 8),
@ -935,7 +1059,10 @@ class _MapScreenState extends State<MapScreen> {
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
contentPadding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 12,
),
),
onChanged: (value) {
setSheetState(() {
@ -945,50 +1072,73 @@ class _MapScreenState extends State<MapScreen> {
),
),
...allContacts
.where((contact) =>
query.isEmpty || matchesContactQuery(contact, query))
.where(
(contact) =>
query.isEmpty ||
matchesContactQuery(contact, query),
)
.map((contact) {
return ListTile(
leading: const Icon(Icons.person),
title: Text(contact.name),
onTap: () {
Navigator.pop(sheetContext);
liveConnector.sendMessage(contact, markerText);
},
);
}),
return ListTile(
leading: const Icon(Icons.person),
title: Text(contact.name),
onTap: () {
Navigator.pop(sheetContext);
liveConnector.sendMessage(contact, markerText);
},
);
}),
Padding(
padding: const EdgeInsets.fromLTRB(16, 12, 16, 4),
child: Text(context.l10n.map_sendToChannel, style: const TextStyle(fontWeight: FontWeight.bold)),
child: Text(
context.l10n.map_sendToChannel,
style: const TextStyle(fontWeight: FontWeight.bold),
),
),
if (liveConnector.isLoadingChannels)
const Padding(
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
padding: EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
child: LinearProgressIndicator(),
)
else if (liveConnector.channels.where((c) => !c.isEmpty).isEmpty)
else if (liveConnector.channels
.where((c) => !c.isEmpty)
.isEmpty)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
child: Text(context.l10n.map_noChannelsAvailable),
)
else
...liveConnector.channels.where((c) => !c.isEmpty).map((channel) {
...liveConnector.channels.where((c) => !c.isEmpty).map((
channel,
) {
final isPublic = _isPublicChannel(channel);
final label = channel.name.isEmpty ? 'Channel ${channel.index}' : channel.name;
final label = channel.name.isEmpty
? 'Channel ${channel.index}'
: channel.name;
return ListTile(
leading: Icon(
isPublic ? Icons.public : Icons.tag,
color: isPublic ? Colors.orange : Colors.blue,
),
title: Text(label),
subtitle: isPublic ? Text(context.l10n.channels_publicChannel) : null,
subtitle: isPublic
? Text(context.l10n.channels_publicChannel)
: null,
onTap: () async {
Navigator.pop(sheetContext);
final canSend = isPublic
? await _confirmPublicShare(context, label)
: true;
if (canSend) {
liveConnector.sendChannelMessage(channel, markerText);
liveConnector.sendChannelMessage(
channel,
markerText,
);
}
},
);
@ -1008,12 +1158,17 @@ class _MapScreenState extends State<MapScreen> {
return channel.isPublicChannel;
}
Future<bool> _confirmPublicShare(BuildContext context, String channelLabel) async {
Future<bool> _confirmPublicShare(
BuildContext context,
String channelLabel,
) async {
final result = await showDialog<bool>(
context: context,
builder: (dialogContext) => AlertDialog(
title: Text(context.l10n.map_publicLocationShare),
content: Text(context.l10n.map_publicLocationShareConfirm(channelLabel)),
content: Text(
context.l10n.map_publicLocationShareConfirm(channelLabel),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(dialogContext, false),
@ -1029,7 +1184,10 @@ class _MapScreenState extends State<MapScreen> {
return result ?? false;
}
void _showFilterDialog(BuildContext context, AppSettingsService settingsService) {
void _showFilterDialog(
BuildContext context,
AppSettingsService settingsService,
) {
showDialog(
context: context,
builder: (dialogContext) => AlertDialog(
@ -1133,10 +1291,7 @@ class _MapScreenState extends State<MapScreen> {
const SizedBox(height: 8),
Text(
_getTimeFilterLabel(settings.mapTimeFilterHours),
style: TextStyle(
fontSize: 14,
color: Colors.grey[700],
),
style: TextStyle(fontSize: 14, color: Colors.grey[700]),
),
Slider(
value: _hoursToSliderValue(settings.mapTimeFilterHours),
@ -1176,11 +1331,14 @@ class _MapScreenState extends State<MapScreen> {
if (hours <= 24) {
return (hours / 24) * 40;
} else if (hours <= 168) { // 7 days
} else if (hours <= 168) {
// 7 days
return 40 + ((hours - 24) / (168 - 24)) * 20;
} else if (hours <= 720) { // 30 days
} else if (hours <= 720) {
// 30 days
return 60 + ((hours - 168) / (720 - 168)) * 20;
} else if (hours <= 4380) { // 6 months
} else if (hours <= 4380) {
// 6 months
return 80 + ((hours - 720) / (4380 - 720)) * 19;
} else {
return 100;

View file

@ -57,6 +57,11 @@ class RepeaterHubScreen extends StatelessWidget {
style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Text(
'<${repeater.publicKeyHex.substring(0, 8)}...${repeater.publicKeyHex.substring(repeater.publicKeyHex.length - 8)}>',
style: TextStyle(fontSize: 14, color: Colors.grey[600]),
),
const SizedBox(height: 8),
Text(
repeater.pathLabel,
style: TextStyle(fontSize: 14, color: Colors.grey[600]),

View file

@ -895,7 +895,7 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
),
const SizedBox(height: 16),
DropdownButtonFormField<int>(
value: _bandwidth,
initialValue: _bandwidth,
decoration: InputDecoration(
labelText: l10n.repeater_bandwidth,
border: const OutlineInputBorder(),
@ -917,7 +917,7 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
),
const SizedBox(height: 16),
DropdownButtonFormField<int>(
value: _spreadingFactor,
initialValue: _spreadingFactor,
decoration: InputDecoration(
labelText: l10n.repeater_spreadingFactor,
border: const OutlineInputBorder(),
@ -939,7 +939,7 @@ class _RepeaterSettingsScreenState extends State<RepeaterSettingsScreen> {
),
const SizedBox(height: 16),
DropdownButtonFormField<int>(
value: _codingRate,
initialValue: _codingRate,
decoration: InputDecoration(
labelText: l10n.repeater_codingRate,
border: const OutlineInputBorder(),

View file

@ -1,7 +1,4 @@
import 'dart:async';
import 'dart:convert';
import 'dart:math';
import 'dart:typed_data';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
@ -34,7 +31,6 @@ class _TelemetryScreenState extends State<TelemetryScreen> {
static const int _statusResponseBytes =
_statusPayloadOffset + _statusStatsSize;
Uint8List _tagData = Uint8List(4);
int _timeEstment = 0;
bool _isLoading = false;
bool _isLoaded = false;
@ -64,18 +60,19 @@ class _TelemetryScreenState extends State<TelemetryScreen> {
if (frame[0] == respCodeSent) {
_tagData = frame.sublist(2, 6);
_timeEstment = frame.buffer.asByteData().getUint32(6, Endian.little);
}
// Check if it's a binary response
if (frame[0] == pushCodeBinaryResponse &&
listEquals(frame.sublist(2, 6), _tagData)) {
_handleStatusResponse(context, frame.sublist(6));
if (!mounted) return;
_handleStatusResponse(frame.sublist(6));
}
});
}
void _handleStatusResponse(BuildContext context, Uint8List frame) {
void _handleStatusResponse(Uint8List frame) {
if (!mounted) return;
setState(() {
_parsedTelemetry = CayenneLpp.parseByChannel(frame);
});

View file

@ -86,14 +86,26 @@ class BleDebugLogService extends ChangeNotifier {
}
String _describeFrame(int code, Uint8List frame, bool outgoing, String? note) {
final label = _codeLabel(code);
final label = _codeLabel(code, outgoing: outgoing);
final prefix = outgoing ? 'TX' : 'RX';
final extra = _frameDetail(code, frame);
final noteText = note != null ? '$note' : '';
return '$prefix $label$extra$noteText';
}
String _codeLabel(int code) {
String _codeLabel(int code, {required bool outgoing}) {
if (outgoing) {
return _commandLabel(code) ?? 'CODE_$code';
}
final pushLabel = _pushLabel(code);
if (pushLabel != null) return pushLabel;
final responseLabel = _responseLabel(code);
if (responseLabel != null) return responseLabel;
return 'CODE_$code';
}
String? _commandLabel(int code) {
switch (code) {
case cmdAppStart:
return 'CMD_APP_START';
@ -135,6 +147,13 @@ class BleDebugLogService extends ChangeNotifier {
return 'CMD_SET_CHANNEL';
case cmdGetRadioSettings:
return 'CMD_GET_RADIO_SETTINGS';
default:
return null;
}
}
String? _responseLabel(int code) {
switch (code) {
case respCodeOk:
return 'RESP_CODE_OK';
case respCodeErr:
@ -167,6 +186,13 @@ class BleDebugLogService extends ChangeNotifier {
return 'RESP_CODE_CHANNEL_INFO';
case respCodeRadioSettings:
return 'RESP_CODE_RADIO_SETTINGS';
default:
return null;
}
}
String? _pushLabel(int code) {
switch (code) {
case pushCodeAdvert:
return 'PUSH_CODE_ADVERT';
case pushCodePathUpdated:
@ -184,7 +210,7 @@ class BleDebugLogService extends ChangeNotifier {
case pushCodeNewAdvert:
return 'PUSH_CODE_NEW_ADVERT';
default:
return 'CODE_$code';
return null;
}
}

View file

@ -6,7 +6,6 @@ import 'package:crypto/crypto.dart';
import '../models/contact.dart';
import '../models/message.dart';
import '../models/path_selection.dart';
import 'storage_service.dart';
import 'app_settings_service.dart';
import 'app_debug_log_service.dart';
@ -36,7 +35,6 @@ class MessageRetryService extends ChangeNotifier {
static const int maxRetries = 5;
static const int maxAckHistorySize = 100;
final StorageService _storage;
final Map<String, Timer> _timeoutTimers = {};
final Map<String, Message> _pendingMessages = {};
final Map<String, Contact> _pendingContacts = {};
@ -59,7 +57,7 @@ class MessageRetryService extends ChangeNotifier {
AppDebugLogService? _debugLogService;
Function(String, PathSelection, bool, int?)? _recordPathResultCallback;
MessageRetryService(this._storage);
MessageRetryService();
void initialize({
required Function(Contact, String, int, int) sendMessageCallback,

View file

@ -31,6 +31,7 @@ class _RepeaterLoginDialogState extends State<RepeaterLoginDialog> {
bool _savePassword = false;
bool _isLoading = true;
bool _obscurePassword = true;
String? _loginError;
late MeshCoreConnector _connector;
int _currentAttempt = 0;
static const int _maxAttempts = 5;
@ -79,6 +80,7 @@ class _RepeaterLoginDialogState extends State<RepeaterLoginDialog> {
setState(() {
_isLoggingIn = true;
_currentAttempt = 0;
_loginError = null;
});
try {
@ -134,7 +136,7 @@ class _RepeaterLoginDialogState extends State<RepeaterLoginDialog> {
'Login failed for ${repeater.name}',
tag: 'RepeaterLogin',
);
throw Exception('Wrong password or node is unreachable');
break;
}
appLogger.warn(
'Login attempt ${attempt + 1} timed out after ${timeoutSeconds}s',
@ -156,7 +158,13 @@ class _RepeaterLoginDialogState extends State<RepeaterLoginDialog> {
}
if (loginResult != true) {
throw Exception('Wrong password or node is unreachable');
if (mounted) {
setState(() {
_isLoggingIn = false;
_loginError = context.l10n.login_failedMessage;
});
}
return;
}
// If we got a response, login succeeded
@ -182,13 +190,8 @@ class _RepeaterLoginDialogState extends State<RepeaterLoginDialog> {
if (mounted) {
setState(() {
_isLoggingIn = false;
_loginError = context.l10n.login_failedMessage;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.l10n.login_failed(e.toString())),
backgroundColor: Colors.red,
),
);
}
}
}
@ -261,15 +264,35 @@ class _RepeaterLoginDialogState extends State<RepeaterLoginDialog> {
child: CircularProgressIndicator(),
),
)
: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
l10n.login_repeaterDescription,
style: const TextStyle(fontSize: 14),
),
const SizedBox(height: 16),
if (_loginError != null) ...[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(Icons.error, size: 18, color: Theme.of(context).colorScheme.error),
const SizedBox(width: 8),
Expanded(
child: Text(
_loginError!,
style: TextStyle(
color: Theme.of(context).colorScheme.error,
fontSize: 13,
),
),
),
],
),
const SizedBox(height: 12),
],
TextField(
controller: _passwordController,
obscureText: _obscurePassword,
@ -291,6 +314,13 @@ class _RepeaterLoginDialogState extends State<RepeaterLoginDialog> {
},
),
),
onChanged: (_) {
if (_loginError != null && mounted) {
setState(() {
_loginError = null;
});
}
},
onSubmitted: (_) => _handleLogin(),
autofocus: _passwordController.text.isEmpty,
),
@ -382,6 +412,7 @@ class _RepeaterLoginDialogState extends State<RepeaterLoginDialog> {
),
],
),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),