diff --git a/Localizable.xcstrings b/Localizable.xcstrings index e6f2f5de..ffa11ca7 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -685,7 +685,7 @@ }, "he" : { "stringUnit" : { - "state" : "needs_review", + "state" : "translated", "value" : "%@ האפליקציה תנסה אוטומטית להתחבר מחדש למכשיר המועדף אם ייראה." } }, @@ -743,7 +743,7 @@ }, "he" : { "stringUnit" : { - "state" : "needs_review", + "state" : "translated", "value" : "%@ שגיאה זו בדרך כלל אינה ניתנת לתיקון ללא שכחחת המכשיר בהגדרות מכשיר > בלוטוס ואז להתחבר מחדש למכשיר." } }, @@ -1812,6 +1812,64 @@ } } }, + "Acknowledged" : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bestätigt" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Confirmé" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "מאשר" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Riconosciuto" + } + }, + "pl" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "Potwierdzono" + } + }, + "se" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bekräftad" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Потврђено" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "确认" + } + }, + "zh-Hant-TW" : { + "stringUnit" : { + "state" : "translated", + "value" : "已確認" + } + } + } + }, "Acknowledged by another node" : { "localizations" : { "it" : { @@ -3399,6 +3457,64 @@ } } }, + "Bad Request" : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "Bad Request" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Requête incorrecte" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "בקשה לא תקינה" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Richiesta negativa" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Złe żądanie" + } + }, + "se" : { + "stringUnit" : { + "state" : "translated", + "value" : "Felaktig begäran" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Лош захтев" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "错误请求" + } + }, + "zh-Hant-TW" : { + "stringUnit" : { + "state" : "translated", + "value" : "錯誤請求" + } + } + } + }, "Bandwidth" : { "localizations" : { "de" : { @@ -4443,6 +4559,64 @@ } } }, + "Category" : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kategorie" + } + }, + "fr" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "Category" + } + }, + "he" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "Category" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Categoria" + } + }, + "pl" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "Category" + } + }, + "se" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "Category" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Категорија" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "Category" + } + }, + "zh-Hant-TW" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "Category" + } + } + } + }, "Ch1 Current" : { "localizations" : { "it" : { @@ -5724,62 +5898,7 @@ } }, "config.module.paxcounter.title" : { - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "PAX Counter Config" - } - }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "PAX Counter Config" - } - }, - "he" : { - "stringUnit" : { - "state" : "translated", - "value" : "PAX Counter Config" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Configurazione del contatore PAX" - } - }, - "pl" : { - "stringUnit" : { - "state" : "translated", - "value" : "PAX Counter Config" - } - }, - "se" : { - "stringUnit" : { - "state" : "translated", - "value" : "PAX Räknare Konfiguration" - } - }, - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Подешавања бројача пролазника" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "PAX 计数器配置" - } - }, - "zh-Hant-TW" : { - "stringUnit" : { - "state" : "translated", - "value" : "PAX 計數器設定" - } - } - } + }, "config.module.paxcounter.updateinterval.description" : { "localizations" : { @@ -7744,7 +7863,7 @@ } } }, - "delete" : { + "Delete" : { "localizations" : { "de" : { "stringUnit" : { @@ -7752,12 +7871,6 @@ "value" : "Löschen" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Delete" - } - }, "fr" : { "stringUnit" : { "state" : "translated", @@ -8384,6 +8497,58 @@ } } }, + "Device Configuration" : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gerätekonfiguration" + } + }, + "he" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "Device Configuration" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Configurazione del dispositivo" + } + }, + "pl" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "Device Configuration" + } + }, + "se" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enhetsinställningar" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подешавања уређаја" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "设备配置" + } + }, + "zh-Hant-TW" : { + "stringUnit" : { + "state" : "translated", + "value" : "設備設定" + } + } + } + }, "Device GPS" : { "localizations" : { "de" : { @@ -8656,64 +8821,6 @@ } } }, - "device.configuration" : { - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Gerätekonfiguration" - } - }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Device Configuration" - } - }, - "he" : { - "stringUnit" : { - "state" : "translated", - "value" : "Device Configuration" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Configurazione del dispositivo" - } - }, - "pl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Device Configuration" - } - }, - "se" : { - "stringUnit" : { - "state" : "translated", - "value" : "Enhetsinställningar" - } - }, - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Подешавања уређаја" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "设备配置" - } - }, - "zh-Hant-TW" : { - "stringUnit" : { - "state" : "translated", - "value" : "設備設定" - } - } - } - }, "device.metrics.delete" : { "localizations" : { "en" : { @@ -9704,13 +9811,13 @@ }, "fr" : { "stringUnit" : { - "state" : "needs_review", + "state" : "translated", "value" : "Combinaison des modes ROUTER et CLIENT. Pas pour les appareils mobiles." } }, "he" : { "stringUnit" : { - "state" : "needs_review", + "state" : "translated", "value" : "קומבינציה של ROUTER וCLIENT. לא למכשירים ניידים." } }, @@ -11319,6 +11426,34 @@ } } }, + "Encrypted Send Failed" : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Verschlüsseltes Senden fehlgeschlagen" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Invio crittografato fallito" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Шифровано слање није успело" + } + }, + "zh-Hant-TW" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "加密傳送失敗" + } + } + } + }, "Encryption Enabled" : { "localizations" : { "it" : { @@ -11805,29 +11940,23 @@ } } }, - "export" : { + "Export" : { "localizations" : { "de" : { "stringUnit" : { - "state" : "translated", - "value" : "Export" - } - }, - "en" : { - "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Export" } }, "fr" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Export" } }, "he" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Export" } }, @@ -11839,13 +11968,13 @@ }, "pl" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Export" } }, "se" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Export" } }, @@ -11857,7 +11986,7 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Export" } }, @@ -13978,7 +14107,7 @@ } } }, - "heard" : { + "Heard" : { "localizations" : { "de" : { "stringUnit" : { @@ -13986,12 +14115,6 @@ "value" : "Gehört" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Heard" - } - }, "fr" : { "stringUnit" : { "state" : "translated", @@ -14612,7 +14735,7 @@ } } }, - "hybrid" : { + "Hybrid" : { "localizations" : { "de" : { "stringUnit" : { @@ -14676,7 +14799,7 @@ } } }, - "hybrid.flyover" : { + "Hybrid Flyover" : { "localizations" : { "de" : { "stringUnit" : { @@ -15086,6 +15209,26 @@ } } }, + "Ignores observed messages from foreign meshes like Local Only, but takes it step further by also ignoring messages from nodes not already in the node's known list." : { + "localizations" : { + "zh-Hant-TW" : { + "stringUnit" : { + "state" : "translated", + "value" : "忽略來自其他 Mesh 的訊息(像 Local Only 那樣),並更進一步連來自不在該節點已知清單中的節點所發出的訊息也一併忽略。" + } + } + } + }, + "Ignores observed messages from foreign meshes that are open or those which it cannot decrypt. Only rebroadcasts message on the nodes local primary / secondary channels." : { + "localizations" : { + "zh-Hant-TW" : { + "stringUnit" : { + "state" : "translated", + "value" : "忽略來自其他 Mesh 的訊息(例如開放的或無法解密的),只會在該節點的本地主要/次要頻道上重新轉發訊息。" + } + } + } + }, "Import Route" : { "localizations" : { "it" : { @@ -15180,12 +15323,6 @@ "value" : "Unvollständig" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Incomplete" - } - }, "fr" : { "stringUnit" : { "state" : "translated", @@ -15194,25 +15331,25 @@ }, "he" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Incomplete" } }, "it" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Incompleto" } }, "pl" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Incomplete" } }, "se" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Incomplete" } }, @@ -15224,7 +15361,7 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Incomplete" } }, @@ -18198,70 +18335,6 @@ } } }, - "log.category" : { - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Kategorie" - } - }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Category" - } - }, - "fr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Category" - } - }, - "he" : { - "stringUnit" : { - "state" : "translated", - "value" : "Category" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Categoria" - } - }, - "pl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Category" - } - }, - "se" : { - "stringUnit" : { - "state" : "translated", - "value" : "Category" - } - }, - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Категорија" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "Category" - } - }, - "zh-Hant-TW" : { - "stringUnit" : { - "state" : "translated", - "value" : "Category" - } - } - } - }, "log.level" : { "localizations" : { "de" : { @@ -19678,6 +19751,64 @@ } } }, + "Max Retransmission Reached" : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Maximale Wiederholungen erreicht" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nombre maximum de retransmissions atteint" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "הגיע למקסימום השליחות מדש" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Raggiunta la massima ritrasmissione" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Osiągnięto limit retransmisji" + } + }, + "se" : { + "stringUnit" : { + "state" : "translated", + "value" : "Max antal omsändningar nått" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Достигнут максималан број поновних слања" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "已达到最大重试次数" + } + }, + "zh-Hant-TW" : { + "stringUnit" : { + "state" : "translated", + "value" : "已達到最大重試次數" + } + } + } + }, "medium.range.fast" : { "localizations" : { "en" : { @@ -20924,40 +21055,6 @@ } } }, - "mesh.log.paxcounter.config %@" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "PAX Counter config received: %@" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Configurazione del contatore PAX ricevuta: %@" - } - }, - "se" : { - "stringUnit" : { - "state" : "translated", - "value" : "PAX-räknarkonfiguration mottagen: %@" - } - }, - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Конфигурација PAX бројача примљена: %@" - } - }, - "zh-Hant-TW" : { - "stringUnit" : { - "state" : "translated", - "value" : "PAX Counter config received: %@" - } - } - } - }, "mesh.log.position.config %@" : { "localizations" : { "de" : { @@ -22187,6 +22284,9 @@ } } } + }, + "message" : { + }, "Message" : { "localizations" : { @@ -22330,7 +22430,7 @@ } } }, - "messages" : { + "Messages" : { "localizations" : { "de" : { "stringUnit" : { @@ -22338,15 +22438,9 @@ "value" : "Nachrichten" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Messages" - } - }, "fr" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Messages" } }, @@ -22394,34 +22488,6 @@ } } }, - "Messages" : { - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Nachrichten" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Messaggi" - } - }, - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Поруке" - } - }, - "zh-Hant-TW" : { - "stringUnit" : { - "state" : "translated", - "value" : "訊息" - } - } - } - }, "Messages separate with |" : { "localizations" : { "de" : { @@ -22582,7 +22648,7 @@ }, "fr" : { "stringUnit" : { - "state" : "needs_review", + "state" : "translated", "value" : "Mode" } }, @@ -23352,6 +23418,70 @@ } } }, + "No Channel" : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kein Kanal" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No Channel" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pas de canal" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "אין ערוץ" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nessun canale" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Brak kanału" + } + }, + "se" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingen kanal" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нема канала" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "没有频道" + } + }, + "zh-Hant-TW" : { + "stringUnit" : { + "state" : "translated", + "value" : "没有頻道" + } + } + } + }, "No Connected Node" : { "localizations" : { "de" : { @@ -23430,6 +23560,70 @@ } } }, + "No Interface" : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keine Schnittstelle" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No Interface" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pas d'interface" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "אין ממשק" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nessuna interfaccia" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Brak interfejsu" + } + }, + "se" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inget gränssnitt" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нема интерфејса" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "无连接" + } + }, + "zh-Hant-TW" : { + "stringUnit" : { + "state" : "translated", + "value" : "無連接" + } + } + } + }, "No PIN (Just Works)" : { "localizations" : { "de" : { @@ -23544,6 +23738,134 @@ } } }, + "No Response" : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keine Antwort" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No Response" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pas de réponse" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "אין תגובה" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nessuna risposta" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Brak odpowiedzi" + } + }, + "se" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inget svar" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нема одговора" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "无响应" + } + }, + "zh-Hant-TW" : { + "stringUnit" : { + "state" : "translated", + "value" : "無回應" + } + } + } + }, + "No Route" : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keine Route" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No Route" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pas de route" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "אין מסלול" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nessun percorso" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Brak trasy" + } + }, + "se" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingen rutt" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нема руте" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "找不到目标" + } + }, + "zh-Hant-TW" : { + "stringUnit" : { + "state" : "translated", + "value" : "找不到目標" + } + } + } + }, "Node" : { "localizations" : { "de" : { @@ -23948,6 +24270,70 @@ } } }, + "Not Authorized" : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nicht authorisiert" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Not Authorized" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Non autorisé" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "לא מאושר" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Non autorizzato" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nieautoryzowany" + } + }, + "se" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inte auktoriserad" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Није ауторизовано" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "未授权" + } + }, + "zh-Hant-TW" : { + "stringUnit" : { + "state" : "translated", + "value" : "未授權" + } + } + } + }, "Not Present" : { "localizations" : { "fr" : { @@ -24528,6 +24914,26 @@ } } }, + "Only permitted for SENSOR, TRACKER and TAK_TRACKER roles, this will inhibit all rebroadcasts, not unlike CLIENT_MUTE role." : { + "localizations" : { + "zh-Hant-TW" : { + "stringUnit" : { + "state" : "translated", + "value" : "僅允許用於 SENSOR、TRACKER 和 TAK_TRACKER 角色,啟用後會禁止所有訊息的重新廣播,效果類似於 CLIENT_MUTE 角色。" + } + } + } + }, + "Only rebroadcasts packets from the core portnums: NodeInfo, Text, Position, Telemetry, and Routing." : { + "localizations" : { + "zh-Hant-TW" : { + "stringUnit" : { + "state" : "translated", + "value" : "僅會重傳來自核心 portnum 的封包:NodeInfo、Text、Position、Telemetry 和 Routing" + } + } + } + }, "Open Settings" : { "localizations" : { "de" : { @@ -24648,12 +25054,6 @@ "value" : "Optionen" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Options" - } - }, "fr" : { "stringUnit" : { "state" : "translated", @@ -24928,12 +25328,6 @@ "value" : "Pairing Modus" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Pairing Mode" - } - }, "fr" : { "stringUnit" : { "state" : "translated", @@ -25000,7 +25394,7 @@ }, "he" : { "stringUnit" : { - "state" : "needs_review", + "state" : "translated", "value" : "סיסמא" } }, @@ -25128,7 +25522,7 @@ }, "pl" : { "stringUnit" : { - "state" : "needs_review", + "state" : "translated", "value" : "PAX Counter" } }, @@ -25158,6 +25552,86 @@ } } }, + "PAX Counter Config" : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "PAX Counter Config" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "PAX Counter Config" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Configurazione del contatore PAX" + } + }, + "pl" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "PAX Counter Config" + } + }, + "se" : { + "stringUnit" : { + "state" : "translated", + "value" : "PAX Räknare Konfiguration" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подешавања бројача пролазника" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "PAX 计数器配置" + } + }, + "zh-Hant-TW" : { + "stringUnit" : { + "state" : "translated", + "value" : "PAX 計數器設定" + } + } + } + }, + "PAX Counter config received: %@" : { + "localizations" : { + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Configurazione del contatore PAX ricevuta: %@" + } + }, + "se" : { + "stringUnit" : { + "state" : "translated", + "value" : "PAX-räknarkonfiguration mottagen: %@" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Конфигурација PAX бројача примљена: %@" + } + }, + "zh-Hant-TW" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "PAX Counter config received: %@" + } + } + } + }, "paxcounter.ble" : { "localizations" : { "en" : { @@ -25733,19 +26207,13 @@ "localizations" : { "de" : { "stringUnit" : { - "state" : "translated", - "value" : "Position" - } - }, - "en" : { - "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Position" } }, "fr" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Position" } }, @@ -25769,7 +26237,7 @@ }, "se" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Position" } }, @@ -27157,6 +27625,16 @@ } } }, + "Rebroadcast any observed message, if it was on our private channel or from another mesh with the same lora params." : { + "localizations" : { + "zh-Hant-TW" : { + "stringUnit" : { + "state" : "translated", + "value" : "只要是在私人頻道上,或是來自使用相同 LoRa 參數的其他 Mesh 的訊息,都會進行重新廣播。" + } + } + } + }, "Rebroadcast Mode" : { "localizations" : { "it" : { @@ -27207,6 +27685,70 @@ } } }, + "Received a negative acknowledgment" : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Negative Empfangsbestätigung empfangen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Received a negative acknowledgment" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Accusé de réception négatif reçu" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "התקבל אישור מסירה שלילי" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ricevuto un riscontro negativo" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otrzymano negatywne potwierdzenie" + } + }, + "se" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mottog ett negativt kvitto" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Примљено негативно признање" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "收到否认" + } + }, + "zh-Hant-TW" : { + "stringUnit" : { + "state" : "translated", + "value" : "收到 NACK(否定確認)" + } + } + } + }, "received.ack" : { "localizations" : { "de" : { @@ -27419,6 +27961,70 @@ } } }, + "Regional Duty Cycle Limit Reached" : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Regionale Einschaltdauergrenze erreicht" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Regional Duty Cycle Limit Reached" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Limite du cycle de service régional atteinte" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "הגיע למקסימום שימוש אזורי לשעה זו" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Raggiunto il limite del ciclo di lavoro regionale" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Osiągnięto regionalny limit cyklu pracy" + } + }, + "se" : { + "stringUnit" : { + "state" : "translated", + "value" : "Regionala sändningsgränsen nådd" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Достигнут регионални лимит радног циклуса" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "已达到当前区域循环周期发射上限" + } + }, + "zh-Hant-TW" : { + "stringUnit" : { + "state" : "translated", + "value" : "已達到頻道占用循環週期發射上限" + } + } + } + }, "relativetimeofday.afternoon" : { "localizations" : { "de" : { @@ -27840,6 +28446,9 @@ } } } + }, + "Replying to a message" : { + }, "Request Legacy Admin: %@" : { "localizations" : { @@ -28924,808 +29533,6 @@ } } }, - "routing.acknowledged" : { - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Bestätigt" - } - }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Acknowledged" - } - }, - "fr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Confirmé" - } - }, - "he" : { - "stringUnit" : { - "state" : "translated", - "value" : "מאשר" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Riconosciuto" - } - }, - "pl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Potwierdzono" - } - }, - "se" : { - "stringUnit" : { - "state" : "translated", - "value" : "Bekräftad" - } - }, - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Потврђено" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "确认" - } - }, - "zh-Hant-TW" : { - "stringUnit" : { - "state" : "translated", - "value" : "已確認" - } - } - } - }, - "routing.badRequest" : { - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Bad Request" - } - }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Bad Request" - } - }, - "fr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Requête incorrecte" - } - }, - "he" : { - "stringUnit" : { - "state" : "translated", - "value" : "בקשה לא תקינה" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Richiesta negativa" - } - }, - "pl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Złe żądanie" - } - }, - "se" : { - "stringUnit" : { - "state" : "translated", - "value" : "Felaktig begäran" - } - }, - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Лош захтев" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "错误请求" - } - }, - "zh-Hant-TW" : { - "stringUnit" : { - "state" : "translated", - "value" : "錯誤請求" - } - } - } - }, - "routing.dutycyclelimit" : { - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Regionale Einschaltdauergrenze erreicht" - } - }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Regional Duty Cycle Limit Reached" - } - }, - "fr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Limite du cycle de service régional atteinte" - } - }, - "he" : { - "stringUnit" : { - "state" : "translated", - "value" : "הגיע למקסימום שימוש אזורי לשעה זו" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Raggiunto il limite del ciclo di lavoro regionale" - } - }, - "pl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Osiągnięto regionalny limit cyklu pracy" - } - }, - "se" : { - "stringUnit" : { - "state" : "translated", - "value" : "Regionala sändningsgränsen nådd" - } - }, - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Достигнут регионални лимит радног циклуса" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "已达到当前区域循环周期发射上限" - } - }, - "zh-Hant-TW" : { - "stringUnit" : { - "state" : "translated", - "value" : "已達到頻道占用循環週期發射上限" - } - } - } - }, - "routing.gotnak" : { - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Negative Empfangsbestätigung empfangen" - } - }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Received a negative acknowledgment" - } - }, - "fr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Accusé de réception négatif reçu" - } - }, - "he" : { - "stringUnit" : { - "state" : "translated", - "value" : "התקבל אישור מסירה שלילי" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Ricevuto un riscontro negativo" - } - }, - "pl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Otrzymano negatywne potwierdzenie" - } - }, - "se" : { - "stringUnit" : { - "state" : "translated", - "value" : "Mottog ett negativt kvitto" - } - }, - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Примљено негативно признање" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "收到否认" - } - }, - "zh-Hant-TW" : { - "stringUnit" : { - "state" : "translated", - "value" : "收到 NACK(否定確認)" - } - } - } - }, - "routing.maxretransmit" : { - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Maximale Wiederholungen erreicht" - } - }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Max Retransmission Reached" - } - }, - "fr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Nombre maximum de retransmissions atteint" - } - }, - "he" : { - "stringUnit" : { - "state" : "translated", - "value" : "הגיע למקסימום השליחות מדש" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Raggiunta la massima ritrasmissione" - } - }, - "pl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Osiągnięto limit retransmisji" - } - }, - "se" : { - "stringUnit" : { - "state" : "translated", - "value" : "Max antal omsändningar nått" - } - }, - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Достигнут максималан број поновних слања" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "已达到最大重试次数" - } - }, - "zh-Hant-TW" : { - "stringUnit" : { - "state" : "translated", - "value" : "已達到最大重試次數" - } - } - } - }, - "routing.nochannel" : { - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Kein Kanal" - } - }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "No Channel" - } - }, - "fr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Pas de canal" - } - }, - "he" : { - "stringUnit" : { - "state" : "translated", - "value" : "אין ערוץ" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Nessun canale" - } - }, - "pl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Brak kanału" - } - }, - "se" : { - "stringUnit" : { - "state" : "translated", - "value" : "Ingen kanal" - } - }, - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Нема канала" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "没有频道" - } - }, - "zh-Hant-TW" : { - "stringUnit" : { - "state" : "translated", - "value" : "没有頻道" - } - } - } - }, - "routing.nointerface" : { - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Keine Schnittstelle" - } - }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "No Interface" - } - }, - "fr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Pas d'interface" - } - }, - "he" : { - "stringUnit" : { - "state" : "translated", - "value" : "אין ממשק" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Nessuna interfaccia" - } - }, - "pl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Brak interfejsu" - } - }, - "se" : { - "stringUnit" : { - "state" : "translated", - "value" : "Inget gränssnitt" - } - }, - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Нема интерфејса" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "无连接" - } - }, - "zh-Hant-TW" : { - "stringUnit" : { - "state" : "translated", - "value" : "無連接" - } - } - } - }, - "routing.noresponse" : { - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Keine Antwort" - } - }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "No Response" - } - }, - "fr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Pas de réponse" - } - }, - "he" : { - "stringUnit" : { - "state" : "translated", - "value" : "אין תגובה" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Nessuna risposta" - } - }, - "pl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Brak odpowiedzi" - } - }, - "se" : { - "stringUnit" : { - "state" : "translated", - "value" : "Inget svar" - } - }, - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Нема одговора" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "无响应" - } - }, - "zh-Hant-TW" : { - "stringUnit" : { - "state" : "translated", - "value" : "無回應" - } - } - } - }, - "routing.noroute" : { - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Keine Route" - } - }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "No Route" - } - }, - "fr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Pas de route" - } - }, - "he" : { - "stringUnit" : { - "state" : "translated", - "value" : "אין מסלול" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Nessun percorso" - } - }, - "pl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Brak trasy" - } - }, - "se" : { - "stringUnit" : { - "state" : "translated", - "value" : "Ingen rutt" - } - }, - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Нема руте" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "找不到目标" - } - }, - "zh-Hant-TW" : { - "stringUnit" : { - "state" : "translated", - "value" : "找不到目標" - } - } - } - }, - "routing.notauthorized" : { - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Nicht authorisiert" - } - }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Not Authorized" - } - }, - "fr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Non autorisé" - } - }, - "he" : { - "stringUnit" : { - "state" : "translated", - "value" : "לא מאושר" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Non autorizzato" - } - }, - "pl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Nieautoryzowany" - } - }, - "se" : { - "stringUnit" : { - "state" : "translated", - "value" : "Inte auktoriserad" - } - }, - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Није ауторизовано" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "未授权" - } - }, - "zh-Hant-TW" : { - "stringUnit" : { - "state" : "translated", - "value" : "未授權" - } - } - } - }, - "routing.pkifailed" : { - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Verschlüsseltes Senden fehlgeschlagen" - } - }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Encrypted Send Failed" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Invio crittografato fallito" - } - }, - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Шифровано слање није успело" - } - }, - "zh-Hant-TW" : { - "stringUnit" : { - "state" : "translated", - "value" : "加密傳送失敗" - } - } - } - }, - "routing.timeout" : { - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Zeitlimit erreicht" - } - }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Timeout" - } - }, - "fr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Délai d'expiration" - } - }, - "he" : { - "stringUnit" : { - "state" : "translated", - "value" : "נגמר הזמן" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Timeout" - } - }, - "pl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Limit czasu" - } - }, - "se" : { - "stringUnit" : { - "state" : "translated", - "value" : "Tidsgräns överskriden" - } - }, - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Време истекло" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "超时" - } - }, - "zh-Hant-TW" : { - "stringUnit" : { - "state" : "translated", - "value" : "逾時" - } - } - } - }, - "routing.toolarge" : { - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Das Paket ist zu groß" - } - }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "The packet is too large" - } - }, - "fr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Le paquet est trop grand" - } - }, - "he" : { - "stringUnit" : { - "state" : "translated", - "value" : "ההודעה ארוכה/גדולה מידי" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Il pacchetto è troppo grande" - } - }, - "pl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Pakiet jest zbyt duży" - } - }, - "se" : { - "stringUnit" : { - "state" : "translated", - "value" : "Paketet är för stort" - } - }, - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Пакет је превелики" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "数据包过大" - } - }, - "zh-Hant-TW" : { - "stringUnit" : { - "state" : "translated", - "value" : "數據包過大" - } - } - } - }, "RSSI %@ dBm" : { "localizations" : { "it" : { @@ -29836,7 +29643,17 @@ } } }, - "satellite" : { + "Same as behavior as ALL but skips packet decoding and simply rebroadcasts them. Only available in Repeater role. Setting this on any other roles will result in ALL behavior." : { + "localizations" : { + "zh-Hant-TW" : { + "stringUnit" : { + "state" : "translated", + "value" : "行為與 ALL 相同,但會略過封包解碼,直接重新廣播。僅在 Repeater 角色中可用;若設定於其他角色,則會自動採用 ALL 的行為。" + } + } + } + }, + "Satellite" : { "localizations" : { "de" : { "stringUnit" : { @@ -29900,7 +29717,7 @@ } } }, - "satellite.flyover" : { + "Satellite Flyover" : { "localizations" : { "de" : { "stringUnit" : { @@ -30048,7 +29865,7 @@ } } }, - "save" : { + "Save" : { "localizations" : { "de" : { "stringUnit" : { @@ -30056,12 +29873,6 @@ "value" : "Speichern" } }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Save" - } - }, "fr" : { "stringUnit" : { "state" : "translated", @@ -30112,34 +29923,6 @@ } } }, - "Save" : { - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Speichern" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Risparmiare" - } - }, - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Сачувај" - } - }, - "zh-Hant-TW" : { - "stringUnit" : { - "state" : "translated", - "value" : "儲存" - } - } - } - }, "Save Channel Settings" : { "localizations" : { "it" : { @@ -32946,7 +32729,7 @@ } } }, - "standard.muted" : { + "Standard Muted" : { "localizations" : { "de" : { "stringUnit" : { @@ -34684,6 +34467,70 @@ } } }, + "The packet is too large" : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Das Paket ist zu groß" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "The packet is too large" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Le paquet est trop grand" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "ההודעה ארוכה/גדולה מידי" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Il pacchetto è troppo grande" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pakiet jest zbyt duży" + } + }, + "se" : { + "stringUnit" : { + "state" : "translated", + "value" : "Paketet är för stort" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пакет је превелики" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "数据包过大" + } + }, + "zh-Hant-TW" : { + "stringUnit" : { + "state" : "translated", + "value" : "數據包過大" + } + } + } + }, "The primary public key authorized to send admin messages to this node." : { "localizations" : { "de" : { @@ -36930,25 +36777,25 @@ }, "it" : { "stringUnit" : { - "state" : "needs_review", + "state" : "translated", "value" : "Tempo di attività" } }, "se" : { "stringUnit" : { - "state" : "needs_review", + "state" : "translated", "value" : "Drifttid" } }, "sr" : { "stringUnit" : { - "state" : "needs_review", + "state" : "translated", "value" : "Време рада" } }, "zh-Hant-TW" : { "stringUnit" : { - "state" : "needs_review", + "state" : "translated", "value" : "已開機時間" } } diff --git a/Meshtastic/Enums/AppSettingsEnums.swift b/Meshtastic/Enums/AppSettingsEnums.swift index 0d84269a..5ddcaad7 100644 --- a/Meshtastic/Enums/AppSettingsEnums.swift +++ b/Meshtastic/Enums/AppSettingsEnums.swift @@ -21,15 +21,15 @@ enum MeshMapTypes: Int, CaseIterable, Identifiable { case .standard: return "Standard".localized case .mutedStandard: - return "standard.muted".localized + return "Standard Muted".localized case .hybrid: - return "hybrid".localized + return "Hybrid".localized case .hybridFlyover: - return "hybrid.flyover".localized + return "Hybrid Flyover".localized case .satellite: - return "satellite".localized + return "Satellite".localized case .satelliteFlyover: - return "satellite.flyover".localized + return "Satellite Flyover".localized } } func MKMapTypeValue() -> MKMapType { diff --git a/Meshtastic/Enums/DeviceEnums.swift b/Meshtastic/Enums/DeviceEnums.swift index 5eb48564..0f132b9d 100644 --- a/Meshtastic/Enums/DeviceEnums.swift +++ b/Meshtastic/Enums/DeviceEnums.swift @@ -168,17 +168,17 @@ enum RebroadcastModes: Int, CaseIterable, Identifiable { var description: String { switch self { case .all: - return "Rebroadcast any observed message, if it was on our private channel or from another mesh with the same lora params." + return "Rebroadcast any observed message, if it was on our private channel or from another mesh with the same lora params.".localized case .allSkipDecoding: - return "Same as behavior as ALL but skips packet decoding and simply rebroadcasts them. Only available in Repeater role. Setting this on any other roles will result in ALL behavior." + return "Same as behavior as ALL but skips packet decoding and simply rebroadcasts them. Only available in Repeater role. Setting this on any other roles will result in ALL behavior.".localized case .localOnly: - return "Ignores observed messages from foreign meshes that are open or those which it cannot decrypt. Only rebroadcasts message on the nodes local primary / secondary channels." + return "Ignores observed messages from foreign meshes that are open or those which it cannot decrypt. Only rebroadcasts message on the nodes local primary / secondary channels.".localized case .knownOnly: - return "Ignores observed messages from foreign meshes like Local Only, but takes it step further by also ignoring messages from nodes not already in the node's known list." + return "Ignores observed messages from foreign meshes like Local Only, but takes it step further by also ignoring messages from nodes not already in the node's known list.".localized case .none: - return "Only permitted for SENSOR, TRACKER and TAK_TRACKER roles, this will inhibit all rebroadcasts, not unlike CLIENT_MUTE role." + return "Only permitted for SENSOR, TRACKER and TAK_TRACKER roles, this will inhibit all rebroadcasts, not unlike CLIENT_MUTE role.".localized case .corePortnums: - return "Only rebroadcasts packets from the core portnums: NodeInfo, Text, Position, Telemetry, and Routing." + return "Only rebroadcasts packets from the core portnums: NodeInfo, Text, Position, Telemetry, and Routing.".localized } } func protoEnumValue() -> Config.DeviceConfig.RebroadcastMode { diff --git a/Meshtastic/Enums/RoutingError.swift b/Meshtastic/Enums/RoutingError.swift index 628e1b3f..985794b3 100644 --- a/Meshtastic/Enums/RoutingError.swift +++ b/Meshtastic/Enums/RoutingError.swift @@ -32,31 +32,31 @@ enum RoutingError: Int, CaseIterable, Identifiable { switch self { case .none: - return "routing.acknowledged".localized + return "Acknowledged".localized case .noRoute: - return "routing.noroute".localized + return "No Route".localized case .gotNak: - return "routing.gotnak".localized + return "Received a negative acknowledgment".localized case .timeout: - return "routing.timeout".localized + return "Timeout".localized case .noInterface: - return "routing.nointerface".localized + return "No Interface".localized case .maxRetransmit: - return "routing.maxretransmit".localized + return "Max Retransmission Reached".localized case .noChannel: - return "routing.nochannel".localized + return "No Channel".localized case .tooLarge: - return "routing.toolarge".localized + return "The packet is too large".localized case .noResponse: - return "routing.noresponse".localized + return "No Response".localized case .dutyCycleLimit: - return "routing.dutycyclelimit".localized + return "Regional Duty Cycle Limit Reached".localized case .badRequest: - return "routing.badRequest".localized + return "Bad Request".localized case .notAuthorized: - return "routing.notauthorized".localized + return "Not Authorized".localized case .pkiFailed: - return "routing.pkifailed".localized + return "Encrypted Send Failed".localized case .pkiUnknownPubkey: return "Unknown public key".localized case .adminBadSessionKey: diff --git a/Meshtastic/Extensions/UserDefaults.swift b/Meshtastic/Extensions/UserDefaults.swift index c255cec2..cdea2fa4 100644 --- a/Meshtastic/Extensions/UserDefaults.swift +++ b/Meshtastic/Extensions/UserDefaults.swift @@ -100,7 +100,7 @@ extension UserDefaults { @UserDefault(.meshMapDistance, defaultValue: 800000) static var meshMapDistance: Double - @UserDefault(.enableMapWaypoints, defaultValue: false) + @UserDefault(.enableMapWaypoints, defaultValue: true) static var enableMapWaypoints: Bool @UserDefault(.enableMapRecentering, defaultValue: false) diff --git a/Meshtastic/Persistence/UpdateCoreData.swift b/Meshtastic/Persistence/UpdateCoreData.swift index b2673477..d8477ee2 100644 --- a/Meshtastic/Persistence/UpdateCoreData.swift +++ b/Meshtastic/Persistence/UpdateCoreData.swift @@ -227,6 +227,7 @@ func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext) let myInfoEntity = MyInfoEntity(context: context) myInfoEntity.myNodeNum = Int64(packet.from) myInfoEntity.rebootCount = 0 + newNode.myInfo = myInfoEntity do { try context.save() Logger.data.info("💾 [NodeInfo] Saved a NodeInfo for node number: \(packet.from.toHex(), privacy: .public)") @@ -236,7 +237,6 @@ func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext) let nsError = error as NSError Logger.data.error("💥 [MyInfoEntity] Error Inserting New Core Data: \(nsError, privacy: .public)") } - newNode.myInfo = myInfoEntity } else { // Update an existing node @@ -1101,7 +1101,7 @@ func upsertExternalNotificationModuleConfigPacket(config: ModuleConfig.ExternalN func upsertPaxCounterModuleConfigPacket(config: ModuleConfig.PaxcounterConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { - let logString = String.localizedStringWithFormat("mesh.log.paxcounter.config %@".localized, String(nodeNum)) + let logString = String.localizedStringWithFormat("PAX Counter config received: %@".localized, String(nodeNum)) Logger.data.info("🧑‍🤝‍🧑 \(logString, privacy: .public)") let fetchNodeInfoRequest = NodeInfoEntity.fetchRequest() diff --git a/Meshtastic/Views/Messages/ChannelList.swift b/Meshtastic/Views/Messages/ChannelList.swift index f4194dc3..1123c4ab 100644 --- a/Meshtastic/Views/Messages/ChannelList.swift +++ b/Meshtastic/Views/Messages/ChannelList.swift @@ -144,7 +144,7 @@ struct ChannelList: View { context.refresh(myInfo, mergeChanges: true) channelSelection = nil } label: { - Text("delete") + Text("Delete") } } } diff --git a/Meshtastic/Views/Messages/ChannelMessageList.swift b/Meshtastic/Views/Messages/ChannelMessageList.swift index e400b5fe..6093d9eb 100644 --- a/Meshtastic/Views/Messages/ChannelMessageList.swift +++ b/Meshtastic/Views/Messages/ChannelMessageList.swift @@ -25,6 +25,8 @@ struct ChannelMessageList: View { @State private var hasReachedBottom = false @State private var gotFirstUnreadMessage: Bool = false + @State private var messageToHighlight: Int64 = 0 + var body: some View { VStack { ScrollViewReader { scrollView in @@ -36,16 +38,33 @@ struct ChannelMessageList: View { if message.replyID > 0 { let messageReply = channel.allPrivateMessages.first(where: { $0.messageId == message.replyID }) HStack { - Text(messageReply?.messagePayload ?? "EMPTY MESSAGE").foregroundColor(.accentColor).font(.caption2) - .padding(10) - .overlay( - RoundedRectangle(cornerRadius: 18) - .stroke(Color.blue, lineWidth: 0.5) - ) - Image(systemName: "arrowshape.turn.up.left.fill") - .symbolRenderingMode(.hierarchical) - .imageScale(.large).foregroundColor(.accentColor) - .padding(.trailing) + Button { + if let messageNum = messageReply?.messageId { + withAnimation(.easeInOut(duration: 0.5)) { + messageToHighlight = messageNum + } + scrollView.scrollTo(messageNum, anchor: .center) + + // Reset highlight after delay + Task { + try? await Task.sleep(nanoseconds: 1_000_000_000) // 1 second + withAnimation(.easeInOut(duration: 0.5)) { + messageToHighlight = -1 + } + } + } + } label: { + Text(messageReply?.messagePayload ?? "EMPTY MESSAGE").foregroundColor(.accentColor).font(.caption2) + .padding(10) + .overlay( + RoundedRectangle(cornerRadius: 18) + .stroke(Color.blue, lineWidth: 0.5) + ) + Image(systemName: "arrowshape.turn.up.left.fill") + .symbolRenderingMode(.hierarchical) + .imageScale(.large).foregroundColor(.accentColor) + .padding(.trailing) + } } } HStack(alignment: .bottom) { @@ -111,6 +130,12 @@ struct ChannelMessageList: View { Spacer(minLength: 50) } } + + .overlay { + RoundedRectangle(cornerRadius: 10) + .stroke(.blue, lineWidth: 2) + .opacity(((messageToHighlight == message.messageId) || (replyMessageId == message.messageId)) ? 1 : 0) + } .padding([.leading, .trailing]) .frame(maxWidth: .infinity) .id(message.messageId) diff --git a/Meshtastic/Views/Messages/MessageContextMenuItems.swift b/Meshtastic/Views/Messages/MessageContextMenuItems.swift index 1d8642a0..dc55a8ce 100644 --- a/Meshtastic/Views/Messages/MessageContextMenuItems.swift +++ b/Meshtastic/Views/Messages/MessageContextMenuItems.swift @@ -104,7 +104,7 @@ struct MessageContextMenuItems: View { Button(role: .destructive) { isShowingDeleteConfirmation = true } label: { - Text("delete") + Text("Delete") Image(systemName: "trash") } } diff --git a/Meshtastic/Views/Messages/Messages.swift b/Meshtastic/Views/Messages/Messages.swift index 6142617b..7580079b 100644 --- a/Meshtastic/Views/Messages/Messages.swift +++ b/Meshtastic/Views/Messages/Messages.swift @@ -65,7 +65,7 @@ struct Messages: View { TipView(MessagesTip(), arrowEdge: .top) } - .navigationTitle("messages") + .navigationTitle("Messages") .navigationBarTitleDisplayMode(.large) .navigationBarItems(leading: MeshtasticLogo()) } content: { diff --git a/Meshtastic/Views/Messages/TextMessageField/TextMessageField.swift b/Meshtastic/Views/Messages/TextMessageField/TextMessageField.swift index 180ec7cd..d60a0381 100644 --- a/Meshtastic/Views/Messages/TextMessageField/TextMessageField.swift +++ b/Meshtastic/Views/Messages/TextMessageField/TextMessageField.swift @@ -15,78 +15,93 @@ struct TextMessageField: View { @State private var sendPositionWithMessage = false var body: some View { - #if targetEnvironment(macCatalyst) - HStack { - if destination.showAlertButton { + VStack { + #if targetEnvironment(macCatalyst) + HStack { + if destination.showAlertButton { + Spacer() + AlertButton { typingMessage += "🔔 Alert Bell! \u{7}" } + } Spacer() - AlertButton { typingMessage += "🔔 Alert Bell! \u{7}" } + RequestPositionButton(action: requestPosition) + TextMessageSize(maxbytes: Self.maxbytes, totalBytes: totalBytes).padding(.trailing) } - Spacer() - RequestPositionButton(action: requestPosition) - TextMessageSize(maxbytes: Self.maxbytes, totalBytes: totalBytes).padding(.trailing) - } - #endif + #endif - HStack(alignment: .top) { - ZStack { - TextField("Message", text: $typingMessage, axis: .vertical) - .onChange(of: typingMessage) { _, value in - totalBytes = value.utf8.count - // Only mess with the value if it is too big - while totalBytes > Self.maxbytes { - typingMessage = String(typingMessage.dropLast()) - totalBytes = typingMessage.utf8.count - } - } - .keyboardType(.default) - .toolbar { - ToolbarItemGroup(placement: .keyboard) { - Button("Dismiss") { - isFocused = false + HStack(alignment: .top) { + if replyMessageId != 0 { + HStack { + Button { + withAnimation(.easeInOut(duration: 0.2)) { + replyMessageId = 0 } - .font(.subheadline) + isFocused = false + } label: { + Image(systemName: "x.circle.fill") + } + Text("Replying to a message") + } + } + + ZStack { + TextField("Message", text: $typingMessage, axis: .vertical) + .onChange(of: typingMessage) { _, value in + totalBytes = value.utf8.count + while totalBytes > Self.maxbytes { + typingMessage = String(typingMessage.dropLast()) + totalBytes = typingMessage.utf8.count + } + } + .keyboardType(.default) + .toolbar { + ToolbarItemGroup(placement: .keyboard) { + Button("Dismiss") { + isFocused = false + } + .font(.subheadline) + + if destination.showAlertButton { + Spacer() + AlertButton { typingMessage += "🔔 Alert Bell Character! \u{7}" } + } - if destination.showAlertButton { Spacer() - AlertButton { typingMessage += "🔔 Alert Bell Character! \u{7}" } + RequestPositionButton(action: requestPosition) + TextMessageSize(maxbytes: Self.maxbytes, totalBytes: totalBytes) } - - Spacer() - RequestPositionButton(action: requestPosition) - TextMessageSize(maxbytes: Self.maxbytes, totalBytes: totalBytes) } - } - .padding(.horizontal, 8) - .focused($isFocused) - .multilineTextAlignment(.leading) - .frame(minHeight: 50) - .keyboardShortcut(.defaultAction) - .onSubmit { - #if targetEnvironment(macCatalyst) - sendMessage() - #endif - } + .padding(.horizontal, 8) + .focused($isFocused) + .multilineTextAlignment(.leading) + .frame(minHeight: 50) + .keyboardShortcut(.defaultAction) + .onSubmit { + #if targetEnvironment(macCatalyst) + sendMessage() + #endif + } - Text(typingMessage) - .opacity(0) - .padding(.all, 0) - } - .overlay(RoundedRectangle(cornerRadius: 20).stroke(.tertiary, lineWidth: 1)) - .padding(.bottom, 15) + Text(typingMessage) + .opacity(0) + .padding(.all, 0) + } + .overlay(RoundedRectangle(cornerRadius: 20).stroke(.tertiary, lineWidth: 1)) + .padding(.bottom, 15) - Button(action: sendMessage) { - Image(systemName: "arrow.up.circle.fill") - .font(.largeTitle) - .foregroundColor(.accentColor) + Button(action: sendMessage) { + Image(systemName: "arrow.up.circle.fill") + .font(.largeTitle) + .foregroundColor(.accentColor) + } } + .padding(.all, 15) } - .padding(.all, 15) } private func requestPosition() { let userLongName = bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : "Unknown" sendPositionWithMessage = true - typingMessage = "📍 " + userLongName + " \(destination.positionShareMessage)." + typingMessage = "📍 " + userLongName + " \(destination.positionShareMessage)." } private func sendMessage() { diff --git a/Meshtastic/Views/Messages/UserList.swift b/Meshtastic/Views/Messages/UserList.swift index 2888a54e..7a7193f2 100644 --- a/Meshtastic/Views/Messages/UserList.swift +++ b/Meshtastic/Views/Messages/UserList.swift @@ -187,7 +187,7 @@ struct UserList: View { deleteUserMessages(user: userSelection!, context: context) context.refresh(node!.user!, mergeChanges: true) } label: { - Text("delete") + Text("Delete") } } } diff --git a/Meshtastic/Views/Messages/UserMessageList.swift b/Meshtastic/Views/Messages/UserMessageList.swift index 9824f621..686decaf 100644 --- a/Meshtastic/Views/Messages/UserMessageList.swift +++ b/Meshtastic/Views/Messages/UserMessageList.swift @@ -25,6 +25,8 @@ struct UserMessageList: View { @State private var hasReachedBottom = false @State private var gotFirstUnreadMessage: Bool = false + @State private var messageToHighlight: Int64 = 0 + var body: some View { VStack { ScrollViewReader { scrollView in @@ -38,16 +40,33 @@ struct UserMessageList: View { if message.replyID > 0 { let messageReply = user.messageList.first(where: { $0.messageId == message.replyID }) HStack { - Text(messageReply?.messagePayload ?? "EMPTY MESSAGE").foregroundColor(.accentColor).font(.caption2) - .padding(10) - .overlay( - RoundedRectangle(cornerRadius: 18) - .stroke(Color.blue, lineWidth: 0.5) - ) - Image(systemName: "arrowshape.turn.up.left.fill") - .symbolRenderingMode(.hierarchical) - .imageScale(.large).foregroundColor(.accentColor) - .padding(.trailing) + Button { + if let messageNum = messageReply?.messageId { + withAnimation(.easeInOut(duration: 0.5)) { + messageToHighlight = messageNum + } + scrollView.scrollTo(messageNum, anchor: .center) + + // Reset highlight after delay + Task { + try? await Task.sleep(nanoseconds: 1_000_000_000) // 1 second + withAnimation(.easeInOut(duration: 0.5)) { + messageToHighlight = -1 + } + } + } + } label: { + Text(messageReply?.messagePayload ?? "EMPTY MESSAGE").foregroundColor(.accentColor).font(.caption2) + .padding(10) + .overlay( + RoundedRectangle(cornerRadius: 18) + .stroke(Color.blue, lineWidth: 0.5) + ) + Image(systemName: "arrowshape.turn.up.left.fill") + .symbolRenderingMode(.hierarchical) + .imageScale(.large).foregroundColor(.accentColor) + .padding(.trailing) + } } } HStack(alignment: .top) { @@ -100,6 +119,11 @@ struct UserMessageList: View { Spacer(minLength: 50) } } + .overlay { + RoundedRectangle(cornerRadius: 10) + .stroke(.blue, lineWidth: 2) + .opacity(((messageToHighlight == message.messageId) || (replyMessageId == message.messageId)) ? 1 : 0) + } .padding([.leading, .trailing]) .frame(maxWidth: .infinity) .id(message.messageId) diff --git a/Meshtastic/Views/Nodes/DetectionSensorLog.swift b/Meshtastic/Views/Nodes/DetectionSensorLog.swift index 89c62be3..af07b9e7 100644 --- a/Meshtastic/Views/Nodes/DetectionSensorLog.swift +++ b/Meshtastic/Views/Nodes/DetectionSensorLog.swift @@ -110,7 +110,7 @@ struct DetectionSensorLog: View { exportString = detectionsToCsv(detections: chartData) isExporting = true } label: { - Label("save", systemImage: "square.and.arrow.down") + Label("Save", systemImage: "square.and.arrow.down") } .buttonStyle(.bordered) .buttonBorderShape(.capsule) diff --git a/Meshtastic/Views/Nodes/DeviceMetricsLog.swift b/Meshtastic/Views/Nodes/DeviceMetricsLog.swift index 0d739c49..c958d1ae 100644 --- a/Meshtastic/Views/Nodes/DeviceMetricsLog.swift +++ b/Meshtastic/Views/Nodes/DeviceMetricsLog.swift @@ -222,7 +222,7 @@ struct DeviceMetricsLog: View { exportString = telemetryToCsvFile(telemetry: deviceMetrics, metricsType: 0) isExporting = true } label: { - Label("save", systemImage: "square.and.arrow.down") + Label("Save", systemImage: "square.and.arrow.down") } .buttonStyle(.bordered) .buttonBorderShape(.capsule) diff --git a/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift b/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift index 7ae9bc50..160f3ef7 100644 --- a/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift +++ b/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift @@ -145,7 +145,7 @@ struct EnvironmentMetricsLog: View { exportString = telemetryToCsvFile(telemetry: environmentMetrics, metricsType: 1) isExporting = true } label: { - Label("save", systemImage: "square.and.arrow.down") + Label("Save", systemImage: "square.and.arrow.down") .imageScale(imageScale) } .buttonStyle(.bordered) diff --git a/Meshtastic/Views/Nodes/Helpers/Map/MapContent/MeshMapContent.swift b/Meshtastic/Views/Nodes/Helpers/Map/MapContent/MeshMapContent.swift index 6a0374f2..4bce572c 100644 --- a/Meshtastic/Views/Nodes/Helpers/Map/MapContent/MeshMapContent.swift +++ b/Meshtastic/Views/Nodes/Helpers/Map/MapContent/MeshMapContent.swift @@ -20,7 +20,7 @@ struct MeshMapContent: MapContent { @Binding var selectedMapLayer: MapLayer // Map Configuration @Binding var selectedPosition: PositionEntity? - @AppStorage("enableMapWaypoints") private var showWaypoints = false + @AppStorage("enableMapWaypoints") private var showWaypoints = true @Binding var selectedWaypoint: WaypointEntity? @FetchRequest(fetchRequest: PositionEntity.allPositionsFetchRequest(), animation: .easeIn) @@ -74,9 +74,9 @@ struct MeshMapContent: MapContent { } } } - .onTapGesture { _ in + .highPriorityGesture(TapGesture().onEnded { _ in selectedPosition = (selectedPosition == position ? nil : position) - } + }) } /// Node History and Route Lines for favorites if let nodePosition = position.nodePosition, @@ -186,7 +186,7 @@ struct MeshMapContent: MapContent { LazyVStack { ZStack { CircleText(text: String(UnicodeScalar(Int(waypoint.icon)) ?? "📍"), color: Color.orange, circleSize: 40) - .onTapGesture(perform: { _ in + .highPriorityGesture(TapGesture().onEnded { _ in selectedWaypoint = (selectedWaypoint == waypoint ? nil : waypoint) }) } diff --git a/Meshtastic/Views/Nodes/Helpers/Map/MapContent/NodeMapContent.swift b/Meshtastic/Views/Nodes/Helpers/Map/MapContent/NodeMapContent.swift index c9fbf95a..2d157979 100644 --- a/Meshtastic/Views/Nodes/Helpers/Map/MapContent/NodeMapContent.swift +++ b/Meshtastic/Views/Nodes/Helpers/Map/MapContent/NodeMapContent.swift @@ -16,7 +16,7 @@ struct NodeMapContent: MapContent { /// Map State User Defaults @AppStorage("meshMapShowNodeHistory") private var showNodeHistory = false @AppStorage("meshMapShowRouteLines") private var showRouteLines = false - @AppStorage("enableMapWaypoints") private var showWaypoints = false + @AppStorage("enableMapWaypoints") private var showWaypoints = true @AppStorage("enableMapConvexHull") private var showConvexHull = false @AppStorage("enableMapTraffic") private var showTraffic: Bool = false @AppStorage("enableMapPointsOfInterest") private var showPointsOfInterest: Bool = false diff --git a/Meshtastic/Views/Nodes/Helpers/Map/PositionPopover.swift b/Meshtastic/Views/Nodes/Helpers/Map/PositionPopover.swift index 97df2327..d3ef18a3 100644 --- a/Meshtastic/Views/Nodes/Helpers/Map/PositionPopover.swift +++ b/Meshtastic/Views/Nodes/Helpers/Map/PositionPopover.swift @@ -52,7 +52,7 @@ struct PositionPopover: View { /// Time Label { if idiom != .phone { - Text("heard".localized + ":") + Text("Heard".localized + ":") } Text(position.time?.lastHeard ?? "unknown") .foregroundColor(.primary) diff --git a/Meshtastic/Views/Nodes/Helpers/Map/WaypointForm.swift b/Meshtastic/Views/Nodes/Helpers/Map/WaypointForm.swift index 736c2114..ad342cbc 100644 --- a/Meshtastic/Views/Nodes/Helpers/Map/WaypointForm.swift +++ b/Meshtastic/Views/Nodes/Helpers/Map/WaypointForm.swift @@ -134,40 +134,44 @@ struct WaypointForm: View { .scrollDismissesKeyboard(.immediately) HStack { Button { - /// Send a new or exiting waypoint - var newWaypoint = Waypoint() - if waypoint.id == 0 { - newWaypoint.id = UInt32.random(in: UInt32(UInt8.max).. 0 ? name : "Dropped Pin" - newWaypoint.description_p = description - // Unicode scalar value for the icon emoji string - let unicodeScalers = icon.unicodeScalars - // First element as an UInt32 - let unicode = unicodeScalers[unicodeScalers.startIndex].value - newWaypoint.icon = unicode - if locked { - if lockedTo == 0 { - newWaypoint.lockedTo = UInt32(bleManager.connectedPeripheral!.num) + if bleManager.isConnected { + /// Send a new or exiting waypoint + var newWaypoint = Waypoint() + if waypoint.id == 0 { + newWaypoint.id = UInt32.random(in: UInt32(UInt8.max).. 0 ? name : "Dropped Pin" + newWaypoint.description_p = description + // Unicode scalar value for the icon emoji string + let unicodeScalers = icon.unicodeScalars + // First element as an UInt32 + let unicode = unicodeScalers[unicodeScalers.startIndex].value + newWaypoint.icon = unicode + if locked { + if lockedTo == 0 { + newWaypoint.lockedTo = UInt32(bleManager.connectedPeripheral!.num) + } else { + newWaypoint.lockedTo = UInt32(lockedTo) + } + } + if expires { + newWaypoint.expire = UInt32(expire.timeIntervalSince1970) + } else { + newWaypoint.expire = 0 + } + if bleManager.sendWaypoint(waypoint: newWaypoint) { + dismiss() + } else { + dismiss() + Logger.mesh.warning("Send waypoint failed") } - } - if expires { - newWaypoint.expire = UInt32(expire.timeIntervalSince1970) } else { - newWaypoint.expire = 0 - } - if bleManager.sendWaypoint(waypoint: newWaypoint) { - dismiss() - } else { - dismiss() - Logger.mesh.warning("Send waypoint failed") + Logger.mesh.warning("Send waypoint failed, node not connected") } } label: { Label("Send", systemImage: "arrow.up") @@ -235,7 +239,7 @@ struct WaypointForm: View { }) } label: { - Label("delete", systemImage: "trash") + Label("Delete", systemImage: "trash") .foregroundColor(.red) } .buttonStyle(.bordered) @@ -364,6 +368,18 @@ struct WaypointForm: View { } } } + .onDisappear { + if waypoint.id == 0 { + // New, unsent waypoint created by the user: delete it + bleManager.context.delete(waypoint) + do { + try bleManager.context.save() + } catch { + bleManager.context.rollback() + Logger.mesh.error("Failed to save context on waypoint deletion: \(error)") + } + } + } .onAppear { if waypoint.id > 0 { let waypoint = getWaypoint(id: Int64(waypoint.id), context: bleManager.context) diff --git a/Meshtastic/Views/Nodes/PaxCounterLog.swift b/Meshtastic/Views/Nodes/PaxCounterLog.swift index ff579eca..58d68bb1 100644 --- a/Meshtastic/Views/Nodes/PaxCounterLog.swift +++ b/Meshtastic/Views/Nodes/PaxCounterLog.swift @@ -187,7 +187,7 @@ struct PaxCounterLog: View { exportString = paxToCsvFile(pax: pax) isExporting = true } label: { - Label("save", systemImage: "square.and.arrow.down") + Label("Save", systemImage: "square.and.arrow.down") } .buttonStyle(.bordered) .buttonBorderShape(.capsule) diff --git a/Meshtastic/Views/Nodes/TraceRouteLog.swift b/Meshtastic/Views/Nodes/TraceRouteLog.swift index bd50f3ac..3d2df721 100644 --- a/Meshtastic/Views/Nodes/TraceRouteLog.swift +++ b/Meshtastic/Views/Nodes/TraceRouteLog.swift @@ -67,7 +67,7 @@ struct TraceRouteLog: View { Logger.data.error("\(error.localizedDescription, privacy: .public)") } } label: { - Label("delete", systemImage: "trash") + Label("Delete", systemImage: "trash") } } } diff --git a/Meshtastic/Views/Settings/AppData.swift b/Meshtastic/Views/Settings/AppData.swift index f1777989..e5535c2c 100644 --- a/Meshtastic/Views/Settings/AppData.swift +++ b/Meshtastic/Views/Settings/AppData.swift @@ -41,7 +41,7 @@ struct AppData: View { Logger.services.error("🗑️ Delete file error: \(error, privacy: .public)") } } label: { - Label("delete", systemImage: "trash") + Label("Delete", systemImage: "trash") } } } icon: { @@ -61,7 +61,7 @@ struct AppData: View { Logger.services.error("🗑️ Delete file error: \(error, privacy: .public)") } } label: { - Label("delete", systemImage: "trash") + Label("Delete", systemImage: "trash") } } } icon: { diff --git a/Meshtastic/Views/Settings/AppLog.swift b/Meshtastic/Views/Settings/AppLog.swift index 5c49f7c4..76f87388 100644 --- a/Meshtastic/Views/Settings/AppLog.swift +++ b/Meshtastic/Views/Settings/AppLog.swift @@ -84,7 +84,7 @@ struct AppLog: View { .foregroundStyle(value.level.color) } .width(min: 85, max: 110) - TableColumn("log.category", value: \.category) + TableColumn("Category", value: \.category) .width(min: 80, max: 130) TableColumn("Message", value: \.composedMessage) { value in Text(value.composedMessage) diff --git a/Meshtastic/Views/Settings/Channels.swift b/Meshtastic/Views/Settings/Channels.swift index 861f0cb3..bff2dbb7 100644 --- a/Meshtastic/Views/Settings/Channels.swift +++ b/Meshtastic/Views/Settings/Channels.swift @@ -219,7 +219,7 @@ struct Channels: View { hasChanges = false } } label: { - Label("save", systemImage: "square.and.arrow.down") + Label("Save", systemImage: "square.and.arrow.down") } .disabled(bleManager.connectedPeripheral == nil)// || !hasChanges)// !hasValidKey) .buttonStyle(.bordered) diff --git a/Meshtastic/Views/Settings/Config/Module/PaxCounterConfig.swift b/Meshtastic/Views/Settings/Config/Module/PaxCounterConfig.swift index 5ef89a17..480f4b94 100644 --- a/Meshtastic/Views/Settings/Config/Module/PaxCounterConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/PaxCounterConfig.swift @@ -22,7 +22,7 @@ struct PaxCounterConfig: View { var body: some View { Form { - ConfigHeader(title: "config.module.paxcounter.title", config: \.powerConfig, node: node, onAppear: setPaxValues) + ConfigHeader(title: "PAX Counter Config", config: \.powerConfig, node: node, onAppear: setPaxValues) Section { Toggle(isOn: $enabled) { diff --git a/Meshtastic/Views/Settings/Config/Module/RangeTestConfig.swift b/Meshtastic/Views/Settings/Config/Module/RangeTestConfig.swift index 7ac35423..f1f56e1a 100644 --- a/Meshtastic/Views/Settings/Config/Module/RangeTestConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/RangeTestConfig.swift @@ -45,7 +45,7 @@ struct RangeTestConfig: View { .font(.callout) Toggle(isOn: $save) { - Label("save", systemImage: "square.and.arrow.down.fill") + Label("Save", systemImage: "square.and.arrow.down.fill") Text("Saves a CSV with the range test message details, currently only available on ESP32 devices with a web server.") } .toggleStyle(SwitchToggleStyle(tint: .accentColor)) diff --git a/Meshtastic/Views/Settings/Config/SaveConfigButton.swift b/Meshtastic/Views/Settings/Config/SaveConfigButton.swift index 0c948a28..36b92443 100644 --- a/Meshtastic/Views/Settings/Config/SaveConfigButton.swift +++ b/Meshtastic/Views/Settings/Config/SaveConfigButton.swift @@ -12,7 +12,7 @@ struct SaveConfigButton: View { Button { isPresentingSaveConfirm = true } label: { - Label("save", systemImage: "square.and.arrow.down") + Label("Save", systemImage: "square.and.arrow.down") } .disabled(bleManager.connectedPeripheral == nil || !hasChanges) .buttonStyle(.bordered) diff --git a/Meshtastic/Views/Settings/Logs/LogDetail.swift b/Meshtastic/Views/Settings/Logs/LogDetail.swift index 864e3c62..31da29d4 100644 --- a/Meshtastic/Views/Settings/Logs/LogDetail.swift +++ b/Meshtastic/Views/Settings/Logs/LogDetail.swift @@ -107,7 +107,7 @@ struct LogDetail: View { /// Category Label { HStack { - Text("log.category".localized + ":") + Text("Category".localized + ":") .font(idiom == .phone ? .caption : .title) .frame(width: idiom == .phone ? 115 : 190, alignment: .trailing) Text(log.category) diff --git a/Meshtastic/Views/Settings/Routes.swift b/Meshtastic/Views/Settings/Routes.swift index 138fab99..23c4fa18 100644 --- a/Meshtastic/Views/Settings/Routes.swift +++ b/Meshtastic/Views/Settings/Routes.swift @@ -154,7 +154,7 @@ struct Routes: View { Logger.data.error("\(error.localizedDescription, privacy: .public)") } } label: { - Label("delete", systemImage: "trash") + Label("Delete", systemImage: "trash") } } @@ -215,7 +215,7 @@ struct Routes: View { .buttonBorderShape(.capsule) .controlSize(.large) - Button("save") { + Button("Save") { selectedRoute?.name = name selectedRoute?.notes = notes selectedRoute?.enabled = enabled @@ -279,7 +279,7 @@ struct Routes: View { exportString = routeToCsvFile(locations: selectedRoute!.locations!.array as? [LocationEntity] ?? []) isExporting = true } label: { - Label("export", systemImage: "square.and.arrow.down") + Label("Export", systemImage: "square.and.arrow.down") } .buttonStyle(.bordered) .buttonBorderShape(.capsule) diff --git a/Meshtastic/Views/Settings/SaveChannelQRCode.swift b/Meshtastic/Views/Settings/SaveChannelQRCode.swift index 0e8e13f1..892df6eb 100644 --- a/Meshtastic/Views/Settings/SaveChannelQRCode.swift +++ b/Meshtastic/Views/Settings/SaveChannelQRCode.swift @@ -43,7 +43,7 @@ struct SaveChannelQRCode: View { showError = true } } label: { - Label("save", systemImage: "square.and.arrow.down") + Label("Save", systemImage: "square.and.arrow.down") } .buttonStyle(.bordered) .buttonBorderShape(.capsule) diff --git a/Meshtastic/Views/Settings/Settings.swift b/Meshtastic/Views/Settings/Settings.swift index 45c9f54a..1e9ab8a7 100644 --- a/Meshtastic/Views/Settings/Settings.swift +++ b/Meshtastic/Views/Settings/Settings.swift @@ -105,7 +105,7 @@ struct Settings: View { } var deviceConfigurationSection: some View { - Section("device.configuration") { + Section("Device Configuration") { NavigationLink(value: SettingsNavigationState.user) { Label { Text("User") diff --git a/Meshtastic/Views/Settings/UserConfig.swift b/Meshtastic/Views/Settings/UserConfig.swift index 644c0077..51f55dbe 100644 --- a/Meshtastic/Views/Settings/UserConfig.swift +++ b/Meshtastic/Views/Settings/UserConfig.swift @@ -141,7 +141,7 @@ struct UserConfig: View { Button { isPresentingSaveConfirm = true } label: { - Label("save", systemImage: "square.and.arrow.down") + Label("Save", systemImage: "square.and.arrow.down") } .disabled(bleManager.connectedPeripheral == nil || !hasChanges) .buttonStyle(.bordered)