From b388a2babfed25f5991ddc150690862381d0142e Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Tue, 13 Feb 2024 21:31:13 -0800 Subject: [PATCH 01/10] Bump version --- Meshtastic.xcodeproj/project.pbxproj | 8 ++++---- Meshtastic/Views/Messages/UserMessageList.swift | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index 9c0fc8fc..c2bbdc19 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -1522,7 +1522,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.2.22; + MARKETING_VERSION = 2.2.23; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -1556,7 +1556,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.2.22; + MARKETING_VERSION = 2.2.23; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -1678,7 +1678,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 2.2.22; + MARKETING_VERSION = 2.2.23; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1711,7 +1711,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 2.2.22; + MARKETING_VERSION = 2.2.23; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/Meshtastic/Views/Messages/UserMessageList.swift b/Meshtastic/Views/Messages/UserMessageList.swift index a8372f38..022d4ec0 100644 --- a/Meshtastic/Views/Messages/UserMessageList.swift +++ b/Meshtastic/Views/Messages/UserMessageList.swift @@ -203,7 +203,7 @@ struct UserMessageList: View { .padding(.bottom) .id(user.messageList.firstIndex(of: message)) - if currentUser && (message.receivedACK && !message.realACK) { + if currentUser && (message.ackError == 5 || message.ackError == 3) || (message.receivedACK && !message.realACK) { RetryButton(message: message) } From 0758aaea56c5c1b4577dee0796f77e5ab76a6872 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Wed, 14 Feb 2024 21:43:29 -0800 Subject: [PATCH 02/10] Clean up the node list --- .../Views/Helpers/LoRaSignalStrength.swift | 7 +- .../Views/Nodes/Helpers/NodeListItem.swift | 99 ++++++++++++------- .../Settings/Config/Module/MQTTConfig.swift | 2 +- 3 files changed, 70 insertions(+), 38 deletions(-) diff --git a/Meshtastic/Views/Helpers/LoRaSignalStrength.swift b/Meshtastic/Views/Helpers/LoRaSignalStrength.swift index d388cb93..9173d93d 100644 --- a/Meshtastic/Views/Helpers/LoRaSignalStrength.swift +++ b/Meshtastic/Views/Helpers/LoRaSignalStrength.swift @@ -28,15 +28,16 @@ struct LoRaSignalStrengthMeter: View { .foregroundColor(getRssiColor(rssi: rssi)) .font(.caption2) } - .padding(.bottom, 2) } else { Gauge(value: Double(signalStrength.rawValue), in: 0...3) { } currentValueLabel: { Image(systemName: "dot.radiowaves.left.and.right") - .font(.caption) + .font(.callout) + .frame(width: 30) Text("Signal \(signalStrength.description)") - .font(.caption) + .font(.callout) .foregroundColor(.gray) + .fixedSize() } .gaugeStyle(.accessoryLinear) .tint(gradient) diff --git a/Meshtastic/Views/Nodes/Helpers/NodeListItem.swift b/Meshtastic/Views/Nodes/Helpers/NodeListItem.swift index 9365cffa..615d54ce 100644 --- a/Meshtastic/Views/Nodes/Helpers/NodeListItem.swift +++ b/Meshtastic/Views/Nodes/Helpers/NodeListItem.swift @@ -21,7 +21,9 @@ struct NodeListItem: View { LazyVStack(alignment: .leading) { HStack { VStack(alignment: .leading) { - CircleText(text: node.user?.shortName ?? "?", color: Color(UIColor(hex: UInt32(node.num))), circleSize: 65) + CircleText(text: node.user?.shortName ?? "?", color: Color(UIColor(hex: UInt32(node.num))), circleSize: 70) + .padding(.trailing, 5) + BatteryLevelCompact(node: node, font: .caption, iconFont: .callout, color: .accentColor) .padding(.trailing, 5) } VStack(alignment: .leading) { @@ -41,7 +43,10 @@ struct NodeListItem: View { .font(.callout) .symbolRenderingMode(.hierarchical) .foregroundColor(.green) - Text("connected").font(.callout) + .frame(width: 30, height: 15) + Text("connected") + .font(UIDevice.current.userInterfaceIdiom == .phone ? .callout : .caption) + .foregroundColor(.gray) } } HStack { @@ -49,8 +54,9 @@ struct NodeListItem: View { .font(.callout) .symbolRenderingMode(.hierarchical) .foregroundColor(node.isOnline ? .green : .orange) + .frame(width: 30, height: 20) LastHeardText(lastHeard: node.lastHeard) - .font(.caption) + .font(UIDevice.current.userInterfaceIdiom == .phone ? .callout : .caption) .foregroundColor(.gray) } HStack { @@ -58,8 +64,9 @@ struct NodeListItem: View { Image(systemName: role?.systemName ?? "figure") .font(.callout) .symbolRenderingMode(.hierarchical) + .frame(width: 30, height: 20) Text("Role: \(role?.name ?? "unknown".localized)") - .font(.caption) + .font(UIDevice.current.userInterfaceIdiom == .phone ? .callout : .caption) .foregroundColor(.gray) } if node.isStoreForwardRouter { @@ -67,8 +74,9 @@ struct NodeListItem: View { Image(systemName: "envelope.arrow.triangle.branch") .font(.callout) .symbolRenderingMode(.hierarchical) + .frame(width: 30, height: 20) Text("storeforward".localized) - .font(.caption) + .font(UIDevice.current.userInterfaceIdiom == .phone ? .callout : .caption) .foregroundColor(.gray) } } @@ -85,7 +93,9 @@ struct NodeListItem: View { Image(systemName: "lines.measurement.horizontal") .font(.callout) .symbolRenderingMode(.hierarchical) - DistanceText(meters: metersAway).font(.caption) + .frame(width: 30, height: 20) + DistanceText(meters: metersAway) + .font(UIDevice.current.userInterfaceIdiom == .phone ? .callout : .caption) .foregroundColor(.gray) } } @@ -98,7 +108,9 @@ struct NodeListItem: View { Image(systemName: "lines.measurement.horizontal") .font(.callout) .symbolRenderingMode(.hierarchical) - DistanceText(meters: metersAway).font(.caption) + .frame(width: 30, height: 20) + DistanceText(meters: metersAway) + .font(UIDevice.current.userInterfaceIdiom == .phone ? .callout : .caption) .foregroundColor(.gray) } } @@ -109,6 +121,7 @@ struct NodeListItem: View { Image(systemName: "fibrechannel") .font(.callout) .symbolRenderingMode(.hierarchical) + .frame(width: 30, height: 20) Text("Channel: \(node.channel)") .foregroundColor(.gray) .font(.caption) @@ -117,44 +130,62 @@ struct NodeListItem: View { Image(systemName: "network") .symbolRenderingMode(.hierarchical) .font(.callout) + .frame(width: 30, height: 20) Text("Via MQTT") .foregroundColor(.gray) .font(.caption) } } + if node.hasPositions || node.hasEnvironmentMetrics || node.hasDetectionSensorMetrics || node.hasTraceRoutes { + HStack { + Image(systemName: "scroll") + .symbolRenderingMode(.hierarchical) + .font(.callout) + .frame(width: 30, height: 20) + Text("Logs:") + .foregroundColor(.gray) + .font(.callout) + if node.hasDeviceMetrics { + Image(systemName: "flipphone") + .symbolRenderingMode(.hierarchical) + .font(.callout) + .frame(width: 30, height: 20) + } + if node.hasPositions { + Image(systemName: "mappin.and.ellipse") + .symbolRenderingMode(.hierarchical) + .font(.callout) + .frame(width: 30, height: 20) + } + if node.hasEnvironmentMetrics { + Image(systemName: "cloud.sun.rain") + .symbolRenderingMode(.hierarchical) + .font(.callout) + .frame(width: 30, height: 20) + } + if node.hasDetectionSensorMetrics { + Image(systemName: "sensor") + .symbolRenderingMode(.hierarchical) + .font(.callout) + .frame(width: 30, height: 20) + } + if node.hasTraceRoutes { + Image(systemName: "signpost.right.and.left") + .symbolRenderingMode(.hierarchical) + .font(.callout) + .frame(width: 30, height: 20) + } + } + .padding(.top) + } if !connected { HStack { let preset = ModemPresets(rawValue: Int(modemPreset)) LoRaSignalStrengthMeter(snr: node.snr, rssi: node.rssi, preset: preset ?? ModemPresets.longFast, compact: true) - .padding(.top, 2) + } + .padding(.top) } - HStack { - BatteryLevelCompact(node: node, font: .caption, iconFont: .callout, color: .accentColor) - - if node.hasPositions { - Image(systemName: "mappin.and.ellipse") - .symbolRenderingMode(.hierarchical) - .font(.callout) - - } - if node.hasEnvironmentMetrics { - Image(systemName: "cloud.sun.rain") - .symbolRenderingMode(.hierarchical) - .font(.callout) - } - if node.hasDetectionSensorMetrics { - Image(systemName: "sensor") - .symbolRenderingMode(.hierarchical) - .font(.callout) - } - if node.hasTraceRoutes { - Image(systemName: "signpost.right.and.left") - .symbolRenderingMode(.hierarchical) - .font(.callout) - } - } - .padding(.top, 3) } .frame(maxWidth: .infinity, alignment: .leading) } diff --git a/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift b/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift index f1ce1aa3..bfaaa031 100644 --- a/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift @@ -33,7 +33,7 @@ struct MQTTConfig: View { if node != nil && node?.loRaConfig != nil { let rc = RegionCodes(rawValue: Int(node?.loRaConfig?.regionCode ?? 0)) if rc?.dutyCycle ?? 0 <= 10 { - Text("Your region has a \(rc?.dutyCycle ?? 0)% duty cycle. MQTT is not advised when you are duty cycle restricted, the extra traffice will quickly overwhelm your LoRa mesh.") + Text("Your region has a \(rc?.dutyCycle ?? 0)% duty cycle. MQTT is not advised when you are duty cycle restricted, the extra traffic will quickly overwhelm your LoRa mesh.") .font(.callout) .foregroundColor(.red) } From b967a617e6133176114f9b1b90eac3c23bed1efd Mon Sep 17 00:00:00 2001 From: nagumii <40807970+nagumii@users.noreply.github.com> Date: Thu, 15 Feb 2024 14:38:41 +0200 Subject: [PATCH 03/10] Create Localizable.strings hebrew --- he.lproj/Localizable.strings | 315 +++++++++++++++++++++++++++++++++++ 1 file changed, 315 insertions(+) create mode 100644 he.lproj/Localizable.strings diff --git a/he.lproj/Localizable.strings b/he.lproj/Localizable.strings new file mode 100644 index 00000000..9a6433a9 --- /dev/null +++ b/he.lproj/Localizable.strings @@ -0,0 +1,315 @@ +/* + Localizable.strings + Meshtastic + + Copyright(c) Garth Vander Houwen on 12/12/22. + +*/ +"about"="אודות"; +"about.meshtastic"="אודות משטסטיק"; +"admin"="אדמין"; +"admin.log"="היסטוריית הודעות אדמין"; +"ago"="עברו"; +"airtime"="זמן אוויר"; +"always.on"="תמיד דלוק"; +"ambient.lighting"="תאורת סביבה"; +"ambient.lighting.config"="הגדרות תאורת סביבה"; +"appsettings"="הגדרות אפליקציה"; +"appsettings.provide.location"="שתף מיקום"; +"appsettings.smartposition"="מיקום חכם"; +"are.you.sure"="האם אתה בטוח?"; +"ascii.capable"="בעל יכולת ASCII"; +"available.radios"="מכשירים זמינים"; +"automatic.detection"="זיהוי אוטומטי"; +"battery.level"="רמת סוללה"; +"ble.name"="שם בלוטוס"; +"ble.connection.timeout %d %@"="התחברות נכשלה לאחר %d נסיונות להתחבר ל%@. יתכן ויש צורך 'לשכוח' את המכשיר בהגדרות מכשיר > בלוטוס."; +"ble.errorcode.6 %@"="%@ האפליקציה תנסה אוטומטית להתחבר מחדש למכשיר המועדף אם ייראה."; +"ble.errorcode.14 %@"="%@ שגיאה זו בדרך כלל אינה ניתנת לתיקון ללא שכחחת המכשיר בהגדרות מכשיר > בלוטוס ואז להתחבר מחדש למכשיר."; +"ble.errorcode.pin %@"="%@ בבקשה נסה שנית להתחבר למכשיר ובדוק את הקוד."; +"bluetooth"="בלוטוס"; +"bluetooth.off"="בלוטוס כבוי"; +"bluetooth.config"="הגדרות בלוטוס"; +"bluetooth.mode.randompin"="קוד אקראי"; +"bluetooth.mode.fixedpin"="קוד קבוע"; +"bluetooth.mode.nopin"="ללא קוד (פשוט עובד)"; +"bluetooth.pairingmode"="מצב הצמדה"; +"bluetooth.pin.validation"="קוד בלוטוס חייבת להיות בת 6 ספרות."; +"bytes"="בייטים"; +"cancel"="בטל"; +"canned.messages"="הודעות קבועות"; +"canned.messages.config"="הגדרות הודעות קבועות"; +"canned.messages.preset.manual"="הגדרה ידנית"; +"canned.messages.preset.rakrotary"="RAK Rotary Encoder Module"; /* left untranslated for clarity */ +"canned.messages.preset.cardkb"="M5 Stack Card KB / RAK Keypad"; /* left untranslated for clarity */ +"channel"="ערוץ"; +"channel.role.disabled"="כבוי"; +"channel.role.primary"="עיקרי"; +"channel.role.secondary"="משני"; +"channel.utilization"="שימוש ערוץ"; +"channels"="ערוצים"; +"clear.app.data"="אפס הגדרות אפליקציה"; +"clear.log"="נקה"; +"close"="סגור"; +"config.save.confirm"="לאחר שמירת הגדרות המכשיר יתחיל מחדש."; +"communicating"="מתקשר עם מכשיר. ."; +"connected.radio"="מכשיר מחובר"; +"connected"="מחובר בבלוטוס"; +"connecting"="מתחבר . ."; +"contacts"="אנשי קשר"; +"contacts %@"="אנשי קשר (%@)"; +"copy"="העתק"; +"current"="נוכחי"; +"default"="ברירת מחדל"; +"delete"="מחק"; +"detection.sensor"="חיישן זיהוי"; +"detection.sensor.config"="הגדרות חיישן זיהוי"; +"detection.sensor.log"="יומן חיישן זיהוי"; +"device"="מכשיר"; +"device.config"="הגדרות מכשיר"; +"device.metrics.delete"="נקה יומן מכשיר?"; +"device.metrics.log"="יומן מכשיר"; +"device.role.client"="אפליקציה מחוברת או מכשיר תקשורת עצמאי."; +"device.role.clientmute"="מכשיר שאינו מעביר הודעות ממכשירים אחרים הלאה."; +"device.role.clienthidden"="מכשיר שרק משדר לפי צורך בכדי לחסוך בחשמל או לשמור על חשאיות."; +"device.role.tracker"="משדר מיקום GPS בעדיפות גבוהה."; +"device.role.lostandfound"="משדר מיקום כהודעה לערוץ ברירת מחדל לעיתים קבועות בכדי לסייע במציאת המכשיר."; +"device.role.sensor"="משדר טלמטריה בעדיפות גבוהה."; +"device.role.tak"="מותאם למערכת ATAK, מקטין תקשורת קבועה."; +"device.role.repeater"="מכשיר תשתית להרחבת המש על ידי העברת הודעות עם דאטה נוסף מינימלי."; +"device.role.router"="מכשיר תשתית להרחבת המש על ידי העברת הודעות. מופיע ברשימת מכשירים."; +"device.role.routerclient"="קומבינציה של ROUTER וCLIENT. לא למכשירים ניידים."; +"direct.messages"="הודעה פרטית"; +"dismiss.keyboard"="סגור מקלדת"; +"display"="צג מכשיר"; +"display.config"="הגדרות צג"; +"distance"="מרחק"; +"disconnect"="התנתק"; +"echo"="הד"; +"email.address"="כתובת דואר אלקטרוני"; +"enabled"="מופעל"; +"encrypted"="מוצפן"; +"external.notification"="נוטיפיקציה חיצונית"; +"external.notification.config"="הגדרות נוטיפיקציה חיצונית"; +"finish"="סיים"; +"firmware.version"="גרסת קושחה"; +"firmware.version.unsupported"="גרסת קושחה אינה נתמכת, לא ניתן להתחבר למכשיר."; +"gas"="דלק"; +"gas.resistance"="Gas Resistance"; /* left untranslated for clarity */ +"generate.qr.code"="צור קוד QR"; +"gpsformat.dec"="פורמט קואורדינטות"; +"gpsformat.dms"="מעלות דקות שניות"; +"gpsformat.utm"="Universal Transverse Mercator"; /* left untranslated for clarity. A translation exists but is frankly indecipherable */ +"gpsformat.mgrs"="Military Grid Reference System"; /* left untranslated for clarity. A translation exists but is frankly indecipherable */ +"gpsformat.olc"="Open Location Code (aka Plus Codes)"; /* left untranslated for clarity. A translation exists but is frankly indecipherable */ +"gpsformat.osgr"="Ordnance Survey Grid Reference"; /* left untranslated for clarity. A translation exists but is frankly indecipherable */ +"gpsmode.disabled"="כבוי"; +"gpsmode.enabled"="מופעל"; +"gpsmode.notPresent"="לא קיים"; +"heard"="נשמע"; +"heard.last"="נשמע לאחרונה"; +"hybrid"="היברידי"; +"hybrid.flyover"="היברידי מלמעלה"; +"include"="כלול"; +"inputevent.none"="ללא"; +"inputevent.up"="למעלה"; +"inputevent.down"="למטה"; +"inputevent.left"="שמאלה"; +"inputevent.right"="ימינה"; +"inputevent.select"="בחר"; +"inputevent.back"="אחרוה"; +"inputevent.cancel"="בטל"; +"interval.one.second"="שניה אחת"; +"interval.two.seconds"="שתי שניות"; +"interval.three.seconds"="שלוש שניות"; +"interval.four.seconds"="ארבע שניות"; +"interval.five.seconds"="חמש שניות"; +"interval.ten.seconds"="עשר שניות"; +"interval.fifteen.seconds"="חמש עשרה שניות"; +"interval.twenty.seconds"="עשרים שניות"; +"interval.twentyfive.seconds"="עשרים וחמש שניות"; +"interval.thirty.seconds"="שלושים שניות"; +"interval.fortyfive.seconds"="ארבעים וחמש שניות"; +"interval.one.minute"="דקה אחת"; +"interval.two.minutes"="שתי דקות"; +"interval.five.minutes"="חמש דקות"; +"interval.ten.minutes"="עשר דקות"; +"interval.fifteen.minutes"="חמש עשרה דקות"; +"interval.thirty.minutes"="שלושים דקות"; +"interval.one.hour"="שעה אחת"; +"interval.two.hours"="שעתיים"; +"interval.three.hours"="שלוש שעות"; +"interval.four.hours"="ארבע שעות"; +"interval.five.hours"="חמש שעות"; +"interval.six.hours"="שש שעות"; +"interval.twelve.hours"="שניים עשר שעות"; +"interval.eighteen.hours"="שמונה עשר שעות"; +"interval.twentyfour.hours"="עשרים וארבע שעות"; +"interval.thirtysix.hours"="שלושים ושש שעות"; +"interval.fortyeight.hours"="ארבעים ושמונה שעות"; +"interval.seventytwo.hours"="שבעים ושתיים שעות"; +"keyboard.type"="סוג מקלדת"; +"logging"="רישום"; +"lora"="לורה"; +"lora.config"="הגדרות לורה"; +"map"="מפת מש"; +"map.type"="סוג ברירת מחדל"; +"map.centering"="מכשיר במרכז"; +"map.tiles.delete"="מחק כל חלקי מפה שמורים"; +"map.recentering"="מרכז מפה אוטומטית"; +"map.use.legacy"="השתמש במפה מדור קודם"; +"map.usertrackingmode"="מצב מעקב אחר משתמש"; +"map.usertrackingmode.follow"="עקוב"; +"map.usertrackingmode.followwithheading"="עקוב עם כיוון"; +"map.usertrackingmode.none"="ללא"; +"mesh.live.activity"="פעילות מש חיה"; +"mesh.log"="יומן מש"; +"mesh.log.ambientlighting.config %@"="הגדרות מודולת תאורת סביבה התקבלו: %@"; +"mesh.log.bluetooth.config %@"="הגדרות בלוטוס התקבלו: %@"; +"mesh.log.cannedmessage.config %@"="הגדרות מודולת תגובות שמורות התקבלו: %@"; +"mesh.log.cannedmessages.messages.get %@"="התבקשו הודעות מודולת הודעות שמורות עבור מכשיר: %@"; +"mesh.log.cannedmessages.messages.received %@"="הודעות עבור הודעות שמורות התקבלו מ-%@"; +"mesh.log.channel.sent %@ %d"="נשלח ערוץ עבור: %@ אינדקס ערוצים %d"; +"mesh.log.channel.received %d %@"="ערוץ %d התקבל מ-%@"; +"mesh.log.device.config %@"="הגדרות מכשיר התקבלו: %@"; +"mesh.log.display.config %@"="הגדרות תצוגה התקבלו: %@"; +"mesh.log.devicemetadata %@"="מבקש מטא-דאטה עבור %@"; +"mesh.log.device.metadata.received %@"="מטא-דאטה של מכשיר התקבל מ-%@"; +"mesh.log.detectionsensor.config %@"="הגדרות מודולת חיישן זיהוי התקבלו: %@"; +"mesh.log.externalnotification.config %@"="הגדרות מודולת נוטיפיקציה חיצונית התקבלו: %@"; +"mesh.log.lora.config %@"="הגדרות לורה התקבלו: %@"; +"mesh.log.lora.config.sent %@"="נשלחו הגדרות לורה עבור: %@"; +"mesh.log.mqtt.config %@"="הגדרות מודולת MQTT התקבלו: %@"; +"mesh.log.myinfo %@"="MyInfo התקבל: %@"; +"mesh.log.network.config %@"="הגדרות רשת התקבלו: %@"; +"mesh.log.nodeinfo.received %@"="מידע אודות מכשיר התקבל: %@"; +"mesh.log.position.config %@"="הגדרות מיקום התקבלו: %@"; +"mesh.log.position.received %@"="הודעת מיקום התקבלו מ-%@"; +"mesh.log.rangetest.config %@"="הגדרות מודולת בדיקת טווח התקבלו: %@"; +"mesh.log.ringtone.config %@"="הגדרות RTTTL רינגטון התקבלו: %@"; +"mesh.log.routing.message %@ %@"="התקבל מסלול עבור בקשה: %@ מצב שליחה: %@"; +"mesh.log.serial.config %@"="הגדרות מודולת תקשורת סיריאלית התקבלו: %@"; +"mesh.log.sharelocation %@"="נשלח מיקום ממכשיר האפל למכשיר המשטסטיק: %@"; +"mesh.log.storeforward.config %@"="הגדרות מודולת שמירה ושליחה התקבלו: %@"; +"mesh.log.telemetry.config %@"="הגדרות מודולת טלמטריה התקבלו: %@"; +"mesh.log.telemetry.received %@"="התקבל טלמטריה עבור: %@"; +"mesh.log.textmessage.received"="הודעת טקסט התקבלה."; +"mesh.log.textmessage.send.failed %@"="שליחת הודעה נכשלה, אין חיבוריות ל-%@"; +"mesh.log.textmessage.sent %@ %@ %@"="נשלחה הודעה %@ מ-%@ ל-%@"; +"mesh.log.traceroute.received.direct %@"="בקשת בדיקת מסלול נשלחה למכשיר: %@ התקבל ישירות."; +"mesh.log.traceroute.received.route %@"="בקשת בדיקת מסלול הצליחה: %@"; +"mesh.log.traceroute.sent %@"="נשלחה בקשת בדיקת מסלול למכשיר: %@"; +"mesh.log.wantconfig %@"="Issuing Want Config to %@"; +"mesh.log.waypoint.sent %@"="נשלחה נקודת ציון מ-%@"; +"mesh.log.waypoint.received %@"="נקודת ציון התקבלה מ-%@"; +"message"="הודעה"; +"message.details"="פרטי הודעה"; +"messages"="הודעות"; +"mode"="מצב"; +"module.configuration"="הגדרות מודולה"; +"mqtt"="MQTT"; /*left untranslated for clarity */ +"mqtt.connect"="התחבר ל-MQTT"; +"mqtt.config"="הגדרות MQTT"; +"mqtt.clientproxy"="MQTT Client Proxy"; /*left untranslated for clarity */ +"mqtt.disconnect"="התנתק מ-MQTT"; +"mqtt.username"="שם משתמש"; +"name"="שם"; +"network"="רשת"; +"network.config"="הגדרות רשת"; +"nodes"="מכשירים"; +"nodes %@"="מכשירים (%@)"; +"no.nodes"="לא נמצאו מכשירי משטסטיק"; +"not.connected"="אין מכשיר מחובר"; +"numbers.punctuation"="מספרים וסימני פיסוק "; +"off"="כבוי"; +"offline"="מנותק"; +"on.boot"="רק בעת הדלקה"; +"options"="הגדרות"; +"password"="סיסמא"; +"pause"="הפסק"; +"phone.gps"="GPS מהטלפון"; +"phone.gps.interval.description"="כל כמה זמן מכשיר הטלפון ישלח את מיקומך למכשיר המשטסטיק. עדכוני מיקום למש מנוהלות על ידי המכשיר."; +"position"="מיקום"; +"position.config"="הגדרות מיקום"; +"preferred.radio"="רדיו מועדף"; +"radio.configuration"="הגדרות רדיו"; +"range.test"="בדיקת טווח"; +"range.test.blocked"="חסום בדיקות טווח"; +"range.test.config"="הגדרות בדיקת טווח"; +"reply"="תגובה"; +"reboot"="התחל מחדש"; +"reboot.node"="התחל מכשיר מחדש??"; +"received.ack"="התקבל אישור מסירה"; +"received.ack.real"="התקבל אישור מסירה מהנמען"; +"resume"="החל מחדש"; +"ringtone"="רינגטון"; +"ringtone.config"="הגדרות רינגטון"; +"route.recorder"="מקליט מסלול"; +"routes"="מסלולים"; +"routing.acknowledged"="מאשר"; +"routing.noroute"="אין מסלול"; +"routing.gotnak"="התקבל אישור מסירה שלילי"; +"routing.timeout"="נגמר הזמן"; +"routing.nointerface"="אין ממשק"; +"routing.maxretransmit"="הגיע למקסימום השליחות מדש"; +"routing.nochannel"="אין ערוץ"; +"routing.toolarge"="ההודעה ארוכה/גדולה מידי"; +"routing.noresponse"="אין תגובה"; +"routing.dutycyclelimit"="הגיע למקסימום שימוש אזורי לשעה זו"; +"routing.badRequest"="בקשה לא תקינה"; +"routing.notauthorized"="לא מאושר"; +"satellite"="לווין"; +"satellite.flyover"="לווין בשמיים"; +"save"="שמור"; +"save.config %@"="שמור הגדרות עבור %@"; +"serial"="סיריאלי"; +"serial.config"="'הגדרות מודולה 'סיריאלי"; +"serial.mode.default"="ברירת מחדל"; +"serial.mode.simple"="פשוט"; +"serial.mode.proto"="Protobufs"; /*left untranslated for clarity */ +"serial.mode.txtmsg"="הודעת טקסט"; +"serial.mode.nmea"="מיקומי NMEA"; +"settings"="הגדרות"; +"share.channels"="שתף ערוצים באמצעות קוד QR"; +"share.position"="שתף מיקום"; +"subscribed"="מחובר למש"; +"select.contact"="בחר איש קשר"; +"select.node"="בחר מכשיר"; +"select.menu.item"="בחר מהתפריט"; +"set.region"="בחר אזור לורה"; +"standard"="סטנדרטי"; +"standard.muted"="סטנדרתי-השתק"; +"start"="החל"; +"storeforward"="שמירה ושליחה"; +"storeforward.config"="הגדרות שמירה ושליחה"; +"storeforward.heartbeat"="שלח דופק"; +"ssid"="שם רשת וויפי"; +"tapback"="תגובה מהירה"; +"tapback.heart"="לב"; +"tapback.thumbsup"="אגודל למעלה"; +"tapback.thumbsdown"="אגודל למטה"; +"tapback.haha"="חחח"; +"tapback.exclamation"="סימן קריאה"; +"tapback.question"="סימן שאלה"; +"tapback.poop"="חרא"; +"telemetry"="טלמטריה (חיישנים)"; +"telemetry.config"="הגדרות טלמטריה"; +"timeout"="זמן קצוב"; +"timestamp"="שעה/תאריך"; +"tip.bluetooth.connect.title"="מכשיר מחובר"; +מראה מידע אודות מכשיר המשטסטיק המחובר כעת לבלוטוס. ניתן לגרור שמאלה להתנתקות או לחיצה ארוכה לראות סטטיסטיקה או להתחיל פעילות. +"tip.bluetooth.connect.message"="מראה מידע אודות מכשיר המשטסטיק המחובר כעת לבלוטוס. ניתן לגרור שמאלה להתנתקות או לחיצה ארוכה לראות סטטיסטיקה או להתחיל פעילות."; +"tip.channels.share.title"="משתף ערוצי משטסטיק"; +"tip.channels.share.message"="במשטסטיק יש עד 8 ערוצים. הראשון הינו הראשי והינו היכן שרוב הפעילות מתבצעת והכרחי. אם לא תשתף את הערוץ הראשי שלך הערוץ הראשון שלך נהיה הערוץ הראשי ברשת השניה. הוא מדבר בערוץ הראשי שלו במשני שלך. ערוץ בעל השם 'admin' הינו לשליטה מרחוק. ערוצים נוספים הינם לקבוצות פרטיות, כל אחת עם מפתח הצפנה משלה."; +"tip.messages.title"="הודעות"; +"tip.messages.message"="ניתן לשלוח הודעות ערוץ (קבוצות צ'אט) והודעות פרטיות. על הודעה ניתן לעשות לחיצה ארוכה בכדי לראות פעולות אפשריות כגון העתק, הגב, תגובה מהירה, מחק ובנוסף לראות מצב שליחה."; +"twitter"="טוויטר"; +"unknown"="לא ידוע"; +"unknown.age"="גיל לא ידוע"; +"unset"="לא נקבע"; +"update.firmware"="עדכן קושחה"; +"update.interval"="זמן בין עדכונים"; +"user"="משתמש"; +"user.details"="פרטי משתמש"; +"voltage"="וולטז'"; +"waiting"="ממתין. . ."; From 904fd79f9e7cc249ee015e38d26f2a470738b487 Mon Sep 17 00:00:00 2001 From: nagumii <40807970+nagumii@users.noreply.github.com> Date: Thu, 15 Feb 2024 20:40:51 +0200 Subject: [PATCH 04/10] Update Localizable.strings Finalized translation of wantconfig. --- he.lproj/Localizable.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/he.lproj/Localizable.strings b/he.lproj/Localizable.strings index 9a6433a9..f84e47a6 100644 --- a/he.lproj/Localizable.strings +++ b/he.lproj/Localizable.strings @@ -199,7 +199,7 @@ "mesh.log.traceroute.received.direct %@"="בקשת בדיקת מסלול נשלחה למכשיר: %@ התקבל ישירות."; "mesh.log.traceroute.received.route %@"="בקשת בדיקת מסלול הצליחה: %@"; "mesh.log.traceroute.sent %@"="נשלחה בקשת בדיקת מסלול למכשיר: %@"; -"mesh.log.wantconfig %@"="Issuing Want Config to %@"; +"mesh.log.wantconfig %@"="שולח בקשת הגדרות ל-%@"; "mesh.log.waypoint.sent %@"="נשלחה נקודת ציון מ-%@"; "mesh.log.waypoint.received %@"="נקודת ציון התקבלה מ-%@"; "message"="הודעה"; From 36f7ae16c608aa4a098c173676a1ea57d8c9210c Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Thu, 15 Feb 2024 19:57:26 -0800 Subject: [PATCH 05/10] Go nuclear on the core data database, delete the data, destroy it and then reset the context. Somehow this does not crash. --- Meshtastic/Views/Bluetooth/Connect.swift | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Meshtastic/Views/Bluetooth/Connect.swift b/Meshtastic/Views/Bluetooth/Connect.swift index 73f36095..1440c56a 100644 --- a/Meshtastic/Views/Bluetooth/Connect.swift +++ b/Meshtastic/Views/Bluetooth/Connect.swift @@ -209,17 +209,19 @@ struct Connect: View { }.padding([.bottom, .top]) } } - .confirmationDialog("Connecting to a new radio will clear all local app data on the phone. The app may close.", isPresented: $presentingSwitchPreferredPeripheral, titleVisibility: .visible) { + .confirmationDialog("Connecting to a new radio will clear all local app data on the phone and will reset all app settings.", isPresented: $presentingSwitchPreferredPeripheral, titleVisibility: .visible) { Button("Connect to new radio?", role: .destructive) { UserDefaults.preferredPeripheralId = selectedPeripherialId if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == CBPeripheralState.connected { bleManager.disconnectPeripheral() } - context.reset() + do { + clearCoreDataDatabase(context: context) PersistenceController.shared.clearDatabase() - + context.reset() + UserDefaults.standard.reset() } catch let error { print("💣 Failed to re-create CoreData database: " + error.localizedDescription) } From 231a160c1e6a34f74d98ce4c3aa84bd28226bcac Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Thu, 15 Feb 2024 20:09:33 -0800 Subject: [PATCH 06/10] Let duty cycle restricted messages be retried --- Meshtastic/Protobufs/meshtastic/mesh.pb.swift | 10 +++++----- Meshtastic/Views/Messages/ChannelMessageList.swift | 2 +- Meshtastic/Views/Messages/UserMessageList.swift | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Meshtastic/Protobufs/meshtastic/mesh.pb.swift b/Meshtastic/Protobufs/meshtastic/mesh.pb.swift index 080d9bfb..018be11c 100644 --- a/Meshtastic/Protobufs/meshtastic/mesh.pb.swift +++ b/Meshtastic/Protobufs/meshtastic/mesh.pb.swift @@ -203,7 +203,7 @@ enum HardwareModel: SwiftProtobuf.Enum { /// /// Heltec Wireless Tracker with ESP32-S3 CPU, built-in GPS, and TFT /// Newer V1.1, version is written on the PCB near the display. - case heltecWirelessTrackerV11 // = 48 + case heltecWirelessTracker // = 48 /// /// Heltec Wireless Paper with ESP32-S3 CPU and E-Ink display @@ -307,7 +307,7 @@ enum HardwareModel: SwiftProtobuf.Enum { case 45: self = .betafpv2400Tx case 46: self = .betafpv900NanoTx case 47: self = .rpiPico - case 48: self = .heltecWirelessTrackerV11 + case 48: self = .heltecWirelessTracker case 49: self = .heltecWirelessPaper case 50: self = .tDeck case 51: self = .tWatchS3 @@ -367,7 +367,7 @@ enum HardwareModel: SwiftProtobuf.Enum { case .betafpv2400Tx: return 45 case .betafpv900NanoTx: return 46 case .rpiPico: return 47 - case .heltecWirelessTrackerV11: return 48 + case .heltecWirelessTracker: return 48 case .heltecWirelessPaper: return 49 case .tDeck: return 50 case .tWatchS3: return 51 @@ -432,7 +432,7 @@ extension HardwareModel: CaseIterable { .betafpv2400Tx, .betafpv900NanoTx, .rpiPico, - .heltecWirelessTrackerV11, + .heltecWirelessTracker, .heltecWirelessPaper, .tDeck, .tWatchS3, @@ -2622,7 +2622,7 @@ extension HardwareModel: SwiftProtobuf._ProtoNameProviding { 45: .same(proto: "BETAFPV_2400_TX"), 46: .same(proto: "BETAFPV_900_NANO_TX"), 47: .same(proto: "RPI_PICO"), - 48: .same(proto: "HELTEC_WIRELESS_TRACKER_V1_1"), + 48: .same(proto: "HELTEC_WIRELESS_TRACKER"), 49: .same(proto: "HELTEC_WIRELESS_PAPER"), 50: .same(proto: "T_DECK"), 51: .same(proto: "T_WATCH_S3"), diff --git a/Meshtastic/Views/Messages/ChannelMessageList.swift b/Meshtastic/Views/Messages/ChannelMessageList.swift index 8b0aa8ab..8c311d7c 100644 --- a/Meshtastic/Views/Messages/ChannelMessageList.swift +++ b/Meshtastic/Views/Messages/ChannelMessageList.swift @@ -225,7 +225,7 @@ struct ChannelMessageList: View { .padding(.bottom) .id(channel.allPrivateMessages.firstIndex(of: message)) - if currentUser && (message.ackError == 5 || message.ackError == 3) { + if currentUser && (message.ackError == 9 || message.ackError == 5 || message.ackError == 3) { RetryButton(message: message) } diff --git a/Meshtastic/Views/Messages/UserMessageList.swift b/Meshtastic/Views/Messages/UserMessageList.swift index 022d4ec0..b595576f 100644 --- a/Meshtastic/Views/Messages/UserMessageList.swift +++ b/Meshtastic/Views/Messages/UserMessageList.swift @@ -203,7 +203,7 @@ struct UserMessageList: View { .padding(.bottom) .id(user.messageList.firstIndex(of: message)) - if currentUser && (message.ackError == 5 || message.ackError == 3) || (message.receivedACK && !message.realACK) { + if currentUser && (message.ackError == 9 || message.ackError == 5 || message.ackError == 3) || (message.receivedACK && !message.realACK) { RetryButton(message: message) } From 3c0e56aeafdb2f97fa2bea1cd1e6a9074983d661 Mon Sep 17 00:00:00 2001 From: Austin Payne Date: Wed, 14 Feb 2024 23:10:30 -0700 Subject: [PATCH 07/10] improvement: avoid duplicate map tile loading Previously a map tile cache miss would cause 2x loading of the tile: once from the remote tile server (which is then written to disk) and once from disk during the default MKTileOverlay.loadTile function. Instead we now directly implement loadTile so that we can avoid the duplicate loading and simply return the fetched remote tile after it is cached, which leads to a noticeable improvement in offline map performance. --- .../Helpers/Map/OfflineTileManager.swift | 30 +++++++++++-------- Meshtastic/Helpers/Map/TileOverlay.swift | 4 ++- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/Meshtastic/Helpers/Map/OfflineTileManager.swift b/Meshtastic/Helpers/Map/OfflineTileManager.swift index 709517c2..269cf9f4 100644 --- a/Meshtastic/Helpers/Map/OfflineTileManager.swift +++ b/Meshtastic/Helpers/Map/OfflineTileManager.swift @@ -103,20 +103,26 @@ class OfflineTileManager: ObservableObject { } } } - func getTileOverlay(for path: MKTileOverlayPath) -> URL { - let file = "\(UserDefaults.mapTileServer.id)-z\(path.z)x\(path.x)y\(path.y).png" - // Check is tile is already available - let tilesUrl = documentsDirectory.appendingPathComponent("tiles").appendingPathComponent(file) - if fileManager.fileExists(atPath: tilesUrl.path) { - return tilesUrl - } else { - if UserDefaults.enableOfflineMaps, UserDefaults.mapTileServer.zoomRange.contains(path.z) { // Get and persist newTile - return persistLocally(path: path) - } else { // Else display empty tile (transparent over Maps tiles) - return Bundle.main.url(forResource: "alpha", withExtension: "png")! - } + + func loadAndCacheTileOverlay(for path: MKTileOverlayPath) throws -> Data { + guard UserDefaults.enableOfflineMaps, UserDefaults.mapTileServer.zoomRange.contains(path.z) else { + return try Data(contentsOf: Bundle.main.url(forResource: "alpha", withExtension: "png")!) + } + + let tilesUrl = documentsDirectory + .appendingPathComponent("tiles") + .appendingPathComponent("\(UserDefaults.mapTileServer.id)-z\(path.z)x\(path.x)y\(path.y)") + .appendingPathExtension("png") + + do { + return try Data(contentsOf: tilesUrl) + } catch let error as NSError where error.code == NSFileReadNoSuchFileError { + let data = try Data(contentsOf: overlay.url(forTilePath: path)) + try data.write(to: tilesUrl) + return data } } + // MARK: Private methods private func computeTileOverlayPaths(boundingBox box: MKMapRect, maxZ: Int = 17) -> [MKTileOverlayPath] { var paths = [MKTileOverlayPath]() diff --git a/Meshtastic/Helpers/Map/TileOverlay.swift b/Meshtastic/Helpers/Map/TileOverlay.swift index 020e30a9..f70befb8 100644 --- a/Meshtastic/Helpers/Map/TileOverlay.swift +++ b/Meshtastic/Helpers/Map/TileOverlay.swift @@ -11,5 +11,7 @@ import MapKit typealias TileCoordinates = (x: Int, y: Int, z: Int) class TileOverlay: MKTileOverlay { - override func url(forTilePath path: MKTileOverlayPath) -> URL { OfflineTileManager.shared.getTileOverlay(for: path) } + override func loadTile(at path: MKTileOverlayPath) async throws -> Data { + return try OfflineTileManager.shared.loadAndCacheTileOverlay(for: path) + } } From 950aa4a51462fc9f9eccbdceb5d4ec48c7e09361 Mon Sep 17 00:00:00 2001 From: Austin Payne Date: Wed, 14 Feb 2024 23:12:27 -0700 Subject: [PATCH 08/10] chore: remove dead OfflineTileManager code --- .../Helpers/Map/OfflineTileManager.swift | 125 +----------------- Meshtastic/Helpers/Map/TileOverlay.swift | 2 - 2 files changed, 7 insertions(+), 120 deletions(-) diff --git a/Meshtastic/Helpers/Map/OfflineTileManager.swift b/Meshtastic/Helpers/Map/OfflineTileManager.swift index 269cf9f4..ab973c1e 100644 --- a/Meshtastic/Helpers/Map/OfflineTileManager.swift +++ b/Meshtastic/Helpers/Map/OfflineTileManager.swift @@ -9,100 +9,29 @@ import Foundation import MapKit class OfflineTileManager: ObservableObject { - enum DownloadStatus { - case download, downloading, downloaded - } static let shared = OfflineTileManager() + init() { print("Documents Directory = \(documentsDirectory)") createDirectoriesIfNecessary() } + // MARK: - Private properties + private var overlay: MKTileOverlay { MKTileOverlay(urlTemplate: UserDefaults.mapTileServer.tileUrl.count > 1 ? UserDefaults.mapTileServer.tileUrl : MapTileServer.openStreetMap.tileUrl) } private var documentsDirectory: URL { fileManager.urls(for: .documentDirectory, in: .userDomainMask).first! } private let fileManager = FileManager.default - // MARK: - Public property - var progress: Float = 0 - var status: DownloadStatus = .download + // MARK: - Public methods + func getAllDownloadedSize() -> String { fileManager.allocatedSizeOfDirectory(at: documentsDirectory.appendingPathComponent("tiles")) } - func hasBeenDownloaded(for boundingBox: MKMapRect) -> Bool { - getEstimatedDownloadSize(for: boundingBox) == 0 - } - func getEstimatedDownloadSize(for boundingBox: MKMapRect) -> Double { - let paths = self.computeTileOverlayPaths(boundingBox: boundingBox) - let count = self.filterTilesAlreadyExisting(paths: paths).count - let size: Double = 30000 // Bytes (average size) - return Double(count) * size - } - func getDownloadedSize(for mapTileLink: MapTileServer) -> Double { - var accumulatedSize: UInt64 = 0 - let mapTiles = try! fileManager.contentsOfDirectory(at: documentsDirectory.appendingPathComponent("tiles"), includingPropertiesForKeys: []) - let matchingTiles = mapTiles.filter { fileName in - let fileNameLower = fileName.absoluteString - return fileNameLower.contains(mapTileLink.id) - } - print("Deleting \(matchingTiles.count) tiles for \(mapTileLink.id)") - for tile in matchingTiles { - let url = documentsDirectory.appendingPathComponent(tile.absoluteString) - accumulatedSize += (try? url.regularFileAllocatedSize()) ?? 0 - } - return Double(accumulatedSize) - } - func getDownloadedSize(for boundingBox: MKMapRect) -> Double { - let paths = self.computeTileOverlayPaths(boundingBox: boundingBox) - var accumulatedSize: UInt64 = 0 - for path in paths { - let file = "tiles/\(UserDefaults.mapTileServer.id)-z\(path.z)x\(path.x)y\(path.y).png" - let url = documentsDirectory.appendingPathComponent(file) - accumulatedSize += (try? url.regularFileAllocatedSize()) ?? 0 - } - return Double(accumulatedSize) - } + func removeAll() { try? fileManager.removeItem(at: documentsDirectory.appendingPathComponent("tiles")) createDirectoriesIfNecessary() } - func remove(for mapTileLink: MapTileServer) { - let mapTiles = try! fileManager.contentsOfDirectory(at: documentsDirectory.appendingPathComponent("tiles"), includingPropertiesForKeys: []) - let matchingTiles = mapTiles.filter { fileName in - let fileNameLower = fileName.absoluteString - return fileNameLower.contains(mapTileLink.id) - } - print("Deleting \(matchingTiles.count) tiles for \(mapTileLink.id)") - for tile in matchingTiles { - try? fileManager.removeItem(at: tile.absoluteURL) - } - } - func remove(for boundingBox: MKMapRect) { - let paths = self.computeTileOverlayPaths(boundingBox: boundingBox) - for path in paths { - let file = "tiles/\(UserDefaults.mapTileServer.id)-z\(path.z)x\(path.x)y\(path.y).png" - let url = documentsDirectory.appendingPathComponent(file) - try? fileManager.removeItem(at: url) - } - self.status = .download - } - /// Download and persist all tiles within the boundingBox - func download(boundingBox: MKMapRect, name: String) { - NetworkManager.shared.runIfNetwork { - self.status = .downloading - self.progress = 0.01 - let paths = self.computeTileOverlayPaths(boundingBox: boundingBox) - let filteredPaths = self.filterTilesAlreadyExisting(paths: paths) - for i in 0.. Data { guard UserDefaults.enableOfflineMaps, UserDefaults.mapTileServer.zoomRange.contains(path.z) else { @@ -124,47 +53,7 @@ class OfflineTileManager: ObservableObject { } // MARK: Private methods - private func computeTileOverlayPaths(boundingBox box: MKMapRect, maxZ: Int = 17) -> [MKTileOverlayPath] { - var paths = [MKTileOverlayPath]() - for z in 1...maxZ { - let topLeft = tranformCoordinate(coordinates: MKMapPoint(x: box.minX, y: box.minY).coordinate, zoom: z) - let topRight = tranformCoordinate(coordinates: MKMapPoint(x: box.maxX, y: box.minY).coordinate, zoom: z) - let bottomLeft = tranformCoordinate(coordinates: MKMapPoint(x: box.minX, y: box.maxY).coordinate, zoom: z) - for x in topLeft.x...topRight.x { - for y in topLeft.y...bottomLeft.y { - paths.append(MKTileOverlayPath(x: x, y: y, z: z, contentScaleFactor: 2)) - } - } - } - return paths - } - private func tranformCoordinate(coordinates: CLLocationCoordinate2D, zoom: Int) -> TileCoordinates { - let lng = coordinates.longitude - let lat = coordinates.latitude - let tileX = Int(floor((lng + 180) / 360.0 * pow(2.0, Double(zoom)))) - let tileY = Int(floor((1 - log( tan( lat * Double.pi / 180.0 ) + 1 / cos( lat * Double.pi / 180.0 )) / Double.pi ) / 2 * pow(2.0, Double(zoom)))) - return (tileX, tileY, zoom) - } - @discardableResult private func persistLocally(path: MKTileOverlayPath) -> URL { - let url = overlay.url(forTilePath: path) - let file = "tiles/\(UserDefaults.mapTileServer.id)-z\(path.z)x\(path.x)y\(path.y).png" - let filename = documentsDirectory.appendingPathComponent(file) - do { - let data = try Data(contentsOf: url) - try data.write(to: filename) - } catch { - print("💀 Save Tile Error = \(error)") - return url - } - return filename - } - private func filterTilesAlreadyExisting(paths: [MKTileOverlayPath]) -> [MKTileOverlayPath] { - paths.filter { - let file = "\(UserDefaults.mapTileServer.id)-z\($0.z)x\($0.x)y\($0.y).png" - let tilesPath = documentsDirectory.appendingPathComponent("tiles").appendingPathComponent(file).path - return !fileManager.fileExists(atPath: tilesPath) - } - } + private func createDirectoriesIfNecessary() { let tiles = documentsDirectory.appendingPathComponent("tiles") try? fileManager.createDirectory(at: tiles, withIntermediateDirectories: true, attributes: [:]) diff --git a/Meshtastic/Helpers/Map/TileOverlay.swift b/Meshtastic/Helpers/Map/TileOverlay.swift index f70befb8..754771df 100644 --- a/Meshtastic/Helpers/Map/TileOverlay.swift +++ b/Meshtastic/Helpers/Map/TileOverlay.swift @@ -8,8 +8,6 @@ import Foundation import MapKit -typealias TileCoordinates = (x: Int, y: Int, z: Int) - class TileOverlay: MKTileOverlay { override func loadTile(at path: MKTileOverlayPath) async throws -> Data { return try OfflineTileManager.shared.loadAndCacheTileOverlay(for: path) From c566f38acbc0af536e0e9bac2bc65fc4c51a36bf Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Thu, 15 Feb 2024 20:15:05 -0800 Subject: [PATCH 09/10] Add hebrew language --- Meshtastic.xcodeproj/project.pbxproj | 3 + he.lproj/Localizable.strings | 314 +++++++++++++++++++++++++++ 2 files changed, 317 insertions(+) create mode 100644 he.lproj/Localizable.strings diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index c2bbdc19..f1e6046b 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -258,6 +258,7 @@ DD295CE92B323ED9002CC4AC /* MeshtasticDataModelV22.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV22.xcdatamodel; sourceTree = ""; }; DD2AD8A7296D2DF9001FF0E7 /* MapViewSwiftUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapViewSwiftUI.swift; sourceTree = ""; }; DD2CC2E52ABFE04E00EDFDA7 /* MeshtasticDataModelV19.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV19.xcdatamodel; sourceTree = ""; }; + DD31EC492B7F18B7006A3995 /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/Localizable.strings; sourceTree = ""; }; DD33DB602B3D1ECC003E1EA0 /* MeshtasticDataModelV 23.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 23.xcdatamodel"; sourceTree = ""; }; DD33DB612B3D27C7003E1EA0 /* FirmwareApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirmwareApi.swift; sourceTree = ""; }; DD3501882852FC3B000FC853 /* Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = ""; }; @@ -1071,6 +1072,7 @@ Base, "zh-Hans", pl, + he, ); mainGroup = DDC2E14B26CE248E0042C5E4; packageReferences = ( @@ -1372,6 +1374,7 @@ DDCDC6CE294821AD004C1DDA /* de */, A65FA974296876BF00A97686 /* zh-Hans */, DDF6B24B2A9C2FC800BA6931 /* pl */, + DD31EC492B7F18B7006A3995 /* he */, ); name = Localizable.strings; sourceTree = ""; diff --git a/he.lproj/Localizable.strings b/he.lproj/Localizable.strings new file mode 100644 index 00000000..707334a0 --- /dev/null +++ b/he.lproj/Localizable.strings @@ -0,0 +1,314 @@ +/* + Localizable.strings + Meshtastic + + Copyright(c) Garth Vander Houwen on 12/12/22. + +*/ +"about"="About"; +"about.meshtastic"="About Meshtastic"; +"admin"="Admin"; +"admin.log"="Admin Message Log"; +"ago"="ago"; +"airtime"="Airtime"; +"always.on"="Always On"; +"ambient.lighting"="Ambient Lighting"; +"ambient.lighting.config"="Ambient Lighting Config"; +"appsettings"="App Settings"; +"appsettings.provide.location"="Share location"; +"appsettings.smartposition"="Smart Position"; +"are.you.sure"="Are you sure?"; +"ascii.capable"="ASCII Capable"; +"available.radios"="Available Radios"; +"automatic.detection"="Automatic Detection"; +"battery.level"="Battery Level"; +"ble.name"="BLE Name"; +"ble.connection.timeout %d %@"="Connection failed after %d attempts to connect to %@. You may need to forget your device under Settings > Bluetooth."; +"ble.errorcode.6 %@"="%@ The app will automatically reconnect to the preferred radio if it comes back in range."; +"ble.errorcode.14 %@"="%@ This error usually cannot be fixed without forgetting the device unders Settings > Bluetooth and re-connecting to the radio."; +"ble.errorcode.pin %@"="%@ Please try connecting again and check the PIN carefully."; +"bluetooth"="Bluetooth"; +"bluetooth.off"="Bluetooth is off"; +"bluetooth.config"="Bluetooth Config"; +"bluetooth.mode.randompin"="Random PIN"; +"bluetooth.mode.fixedpin"="Fixed PIN"; +"bluetooth.mode.nopin"="No PIN (Just Works)"; +"bluetooth.pairingmode"="Pairing Mode"; +"bluetooth.pin.validation"="BLE Pin must be 6 digits long."; +"bytes"="Bytes"; +"cancel"="Cancel"; +"canned.messages"="Canned Messages"; +"canned.messages.config"="Canned Messages Config"; +"canned.messages.preset.manual"="Manual Configuration"; +"canned.messages.preset.rakrotary"="RAK Rotary Encoder Module"; +"canned.messages.preset.cardkb"="M5 Stack Card KB / RAK Keypad"; +"channel"="Channel"; +"channel.role.disabled"="Disabled"; +"channel.role.primary"="Primary"; +"channel.role.secondary"="Secondary"; +"channel.utilization"="Channel Utilization"; +"channels"="Channels"; +"clear.app.data"="Clear App Data"; +"clear.log"="Clear"; +"close"="Close"; +"config.save.confirm"="After config values save the node will reboot."; +"communicating"="Communicating with device. ."; +"connected.radio"="Connected Radio"; +"connected"="Bluetooth Connected"; +"connecting"="Connecting . ."; +"contacts"="Contacts"; +"contacts %@"="Contacts (%@)"; +"copy"="Copy"; +"current"="Current"; +"default"="Default"; +"delete"="Delete"; +"detection.sensor"="Detection Sensor"; +"detection.sensor.config"="Detection Sensor Config"; +"detection.sensor.log"="Detection Sensor Log"; +"device"="Device"; +"device.config"="Device Config"; +"device.metrics.delete"="Delete all device metrics?"; +"device.metrics.log"="Device Metrics Log"; +"device.role.client"="App connected or stand alone messaging device."; +"device.role.clientmute"="Device that does not forward packets from other devices."; +"device.role.clienthidden"="Device that only broadcasts as needed for stealth or power savings."; +"device.role.tracker"="Broadcasts GPS position packets as priority."; +"device.role.lostandfound"="Broadcasts location as message to default channel regularly for to assist with device recovery."; +"device.role.sensor"="Broadcasts telemetry packets as priority."; +"device.role.tak"="Optimized for ATAK system communication, reduces routine broadcasts."; +"device.role.repeater"="Infrastructure node for extending network coverage by relaying messages with minimal overhead. Not visible in Nodes list."; +"device.role.router"="Infrastructure node for extending network coverage by relaying messages. Visible in Nodes list."; +"device.role.routerclient"="Combination of both ROUTER and CLIENT. Not for mobile devices."; +"direct.messages"="Direct Messages"; +"dismiss.keyboard"="Dismiss"; +"display"="Display (Device Screen)"; +"display.config"="Display Config"; +"distance"="Distance"; +"disconnect"="Disconnect"; +"echo"="Echo"; +"email.address"="Email Address"; +"enabled"="Enabled"; +"encrypted"="Encrypted"; +"external.notification"="External Notification"; +"external.notification.config"="External Notification Config"; +"finish"="Finish"; +"firmware.version"="Firmware Version"; +"firmware.version.unsupported"="Unsupported Firmware Version Detected, unable to connect to device."; +"gas"="Gas"; +"gas.resistance"="Gas Resistance"; +"generate.qr.code"="Generate QR Code"; +"gpsformat.dec"="Decimal Degrees Format"; +"gpsformat.dms"="Degrees Minutes Seconds"; +"gpsformat.utm"="Universal Transverse Mercator"; +"gpsformat.mgrs"="Military Grid Reference System"; +"gpsformat.olc"="Open Location Code (aka Plus Codes)"; +"gpsformat.osgr"="Ordnance Survey Grid Reference"; +"gpsmode.disabled"="Disabled"; +"gpsmode.enabled"="Enabled"; +"gpsmode.notPresent"="Not Present"; +"heard"="Heard"; +"heard.last"="Last Heard"; +"hybrid"="Hybrid"; +"hybrid.flyover"="Hybrid Flyover"; +"include"="Include"; +"inputevent.none"="None"; +"inputevent.up"="Up"; +"inputevent.down"="Down"; +"inputevent.left"="Left"; +"inputevent.right"="Right"; +"inputevent.select"="Select"; +"inputevent.back"="Back"; +"inputevent.cancel"="Cancel"; +"interval.one.second"="One Second"; +"interval.two.seconds"="Two Seconds"; +"interval.three.seconds"="Three Seconds"; +"interval.four.seconds"="Four Seconds"; +"interval.five.seconds"="Five Seconds"; +"interval.ten.seconds"="Ten Seconds"; +"interval.fifteen.seconds"="Fifteen Seconds"; +"interval.twenty.seconds"="Twenty Seconds"; +"interval.twentyfive.seconds"="Twenty Five Seconds"; +"interval.thirty.seconds"="Thirty Seconds"; +"interval.fortyfive.seconds"="Forty Five Seconds"; +"interval.one.minute"="One Minute"; +"interval.two.minutes"="Two Minutes"; +"interval.five.minutes"="Five Minutes"; +"interval.ten.minutes"="Ten Minutes"; +"interval.fifteen.minutes"="Fifteen Minutes"; +"interval.thirty.minutes"="Thirty Minutes"; +"interval.one.hour"="One Hour"; +"interval.two.hours"="Two Hours"; +"interval.three.hours"="Three Hours"; +"interval.four.hours"="Four Hours"; +"interval.five.hours"="Five Hours"; +"interval.six.hours"="Six Hours"; +"interval.twelve.hours"="Twelve Hours"; +"interval.eighteen.hours"="Eighteen Hours"; +"interval.twentyfour.hours"="Twenty Four Hours"; +"interval.thirtysix.hours"="Thirty Six Hours"; +"interval.fortyeight.hours"="Forty Eight Hours"; +"interval.seventytwo.hours"="Seventy Two Hours"; +"keyboard.type"="Keyboard Type"; +"logging"="Logging"; +"lora"="LoRa"; +"lora.config"="LoRa Config"; +"map"="Mesh Map"; +"map.type"="Default Type"; +"map.centering"="Centering Mode"; +"map.tiles.delete"="Delete All Map Tiles"; +"map.recentering"="Automatic Re-centering"; +"map.use.legacy"="Use Legacy Mesh Map"; +"map.usertrackingmode"="User tracking mode"; +"map.usertrackingmode.follow"="Follow"; +"map.usertrackingmode.followwithheading"="Follow with heading"; +"map.usertrackingmode.none"="None"; +"mesh.live.activity"="Mesh Live Activity"; +"mesh.log"="Mesh Log"; +"mesh.log.ambientlighting.config %@"="Ambient Lighting module config received: %@"; +"mesh.log.bluetooth.config %@"="Bluetooth config received: %@"; +"mesh.log.cannedmessage.config %@"="Canned Message module config received: %@"; +"mesh.log.cannedmessages.messages.get %@"="Requested Canned Messages Module Messages for node: %@"; +"mesh.log.cannedmessages.messages.received %@"="Canned Messages Messages Received For: %@"; +"mesh.log.channel.sent %@ %d"="Sent a Channel for: %@ Channel Index %d"; +"mesh.log.channel.received %d %@"="Channel %d received from: %@"; +"mesh.log.device.config %@"="Device config received: %@"; +"mesh.log.display.config %@"="Display config received: %@"; +"mesh.log.devicemetadata %@"="Requesting Device Metadata for %@"; +"mesh.log.device.metadata.received %@"="Device Metadata received from: %@"; +"mesh.log.detectionsensor.config %@"="Detection Sensor module config received: %@"; +"mesh.log.externalnotification.config %@"="External Notification module config received: %@"; +"mesh.log.lora.config %@"="LoRa config received: %@"; +"mesh.log.lora.config.sent %@"="Sent a LoRa.Config for: %@"; +"mesh.log.mqtt.config %@"="MQTT module config received: %@"; +"mesh.log.myinfo %@"="MyInfo received: %@"; +"mesh.log.network.config %@"="Network config received: %@"; +"mesh.log.nodeinfo.received %@"="Node info received for: %@"; +"mesh.log.position.config %@"="Positon config received: %@"; +"mesh.log.position.received %@"="Position Packet received from node: %@"; +"mesh.log.rangetest.config %@"="Range Test module config received: %@"; +"mesh.log.ringtone.config %@"="RTTTL Ringtone config received: %@"; +"mesh.log.routing.message %@ %@"="Routing received for RequestID: %@ Ack Status: %@"; +"mesh.log.serial.config %@"="Serial module config received: %@"; +"mesh.log.sharelocation %@"="Sent a Position Packet from the Apple device GPS to node: %@"; +"mesh.log.storeforward.config %@"="Store & Forward module config received: %@"; +"mesh.log.telemetry.config %@"="Telemetry module config received: %@"; +"mesh.log.telemetry.received %@"="Telemetry received for: %@"; +"mesh.log.textmessage.received"="Message received from the text message app."; +"mesh.log.textmessage.send.failed %@"="Message Send Failed, not properly connected to %@"; +"mesh.log.textmessage.sent %@ %@ %@"="Sent message %@ from %@ to %@"; +"mesh.log.traceroute.received.direct %@"="Trace Route request sent to node: %@ was recieived directly."; +"mesh.log.traceroute.received.route %@"="Trace Route request returned: %@"; +"mesh.log.traceroute.sent %@"="Sent a Trace Route Request to node: %@"; +"mesh.log.wantconfig %@"="Issuing Want Config to %@"; +"mesh.log.waypoint.sent %@"="Sent a Waypoint Packet from: %@"; +"mesh.log.waypoint.received %@"="Waypoint Packet received from node: %@"; +"message"="Message"; +"message.details"="Message Details"; +"messages"="Messages"; +"mode"="Mode"; +"module.configuration"="Module Configuration"; +"mqtt"="MQTT"; +"mqtt.connect"="Connect to MQTT"; +"mqtt.config"="MQTT Config"; +"mqtt.clientproxy"="MQTT Client Proxy"; +"mqtt.disconnect"="Disconnect from MQTT"; +"mqtt.username"="Username"; +"name"="Name"; +"network"="Network"; +"network.config"="Network Config"; +"nodes"="Nodes"; +"nodes %@"="Nodes (%@)"; +"no.nodes"="No Meshtastic Nodes Found"; +"not.connected"="No device connected"; +"numbers.punctuation"="Numbers and Punctuation"; +"off"="Off"; +"offline"="Offline"; +"on.boot"="On Boot Only"; +"options"="Options"; +"password"="Password"; +"pause"="Pause"; +"phone.gps"="Phone GPS"; +"phone.gps.interval.description"="How frequently your phone will send your location to the device, location updates to the mesh are managed by the device."; +"position"="Position"; +"position.config"="Position Config"; +"preferred.radio"="Preferred Radio"; +"radio.configuration"="Radio Configuration"; +"range.test"="Range Test"; +"range.test.blocked"="Block Range Test"; +"range.test.config"="Range Test Config"; +"reply"="Reply"; +"reboot"="Reboot"; +"reboot.node"="Reboot node?"; +"received.ack"="Received Ack"; +"received.ack.real"="Recipient Ack"; +"resume"="Resume"; +"ringtone"="Ringtone"; +"ringtone.config"="Ringtone Config"; +"route.recorder"="Route Recorder"; +"routes"="Routes"; +"routing.acknowledged"="Acknowledged"; +"routing.noroute"="No Route"; +"routing.gotnak"="Received a negative acknowledgment"; +"routing.timeout"="Timeout"; +"routing.nointerface"="No Interface"; +"routing.maxretransmit"="Max Retransmission Reached"; +"routing.nochannel"="No Channel"; +"routing.toolarge"="The packet is too large"; +"routing.noresponse"="No Response"; +"routing.dutycyclelimit"="Regional Duty Cycle Limit Reached"; +"routing.badRequest"="Bad Request"; +"routing.notauthorized"="Not Authorized"; +"satellite"="Satellite"; +"satellite.flyover"="Satellite Flyover"; +"save"="Save"; +"save.config %@"="Save Config for %@"; +"serial"="Serial"; +"serial.config"="Serial Config"; +"serial.mode.default"="Default"; +"serial.mode.simple"="Simple"; +"serial.mode.proto"="Protobufs"; +"serial.mode.txtmsg"="Text Message"; +"serial.mode.nmea"="NMEA Positions"; +"settings"="Settings"; +"share.channels"="Share Channels QR Code"; +"share.position"="Share Position"; +"subscribed"="Subscribed to mesh"; +"select.contact"="Select a Contact"; +"select.node"="Select a Node"; +"select.menu.item"="Select an item from the menu"; +"set.region"="Set LoRa Region"; +"standard"="Standard"; +"standard.muted"="Standard Muted"; +"start"="Start"; +"storeforward"="Store & Forward"; +"storeforward.config"="Store & Forward Config"; +"storeforward.heartbeat"="Send Heartbeat"; +"ssid"="SSID"; +"tapback"="Tapback Response"; +"tapback.heart"="Heart"; +"tapback.thumbsup"="Thumbs Up"; +"tapback.thumbsdown"="Thumbs Down"; +"tapback.haha"="HaHa"; +"tapback.exclamation"="Exclamation Mark"; +"tapback.question"="Question Mark"; +"tapback.poop"="Poop"; +"telemetry"="Telemetry (Sensors)"; +"telemetry.config"="Telemetry Config"; +"timeout"="Timeout"; +"timestamp"="Timestamp"; +"tip.bluetooth.connect.title"="Connected Radio"; +"tip.bluetooth.connect.message"="Shows information for the Lora radio currently connected via bluetooth. You can swipe left to disconnect the radio and long press to view stats or start the live activity."; +"tip.channels.share.title"="Sharing Meshtastic Channels"; +"tip.channels.share.message"="In a Meshtastic LoRa Mesh there are up to 8 channels. The first one is the Primary channel where most activity happens and is required. If you don't share your primary channel your first shared channel becomes the primary channel on the other network. It talks on its primary and your secondary channel. A channel with the name 'admin' controls nodes remotely. Other channels are for private groups, each with its own key."; +"tip.messages.title"="Messages"; +"tip.messages.message"="You can send and receive channel (group chats) and direct messages. From any message you can long press to see available actions like copy, reply, tapback and delete as well as delivery details."; +"twitter"="Twitter"; +"unknown"="Unknown"; +"unknown.age"="Unknown Age"; +"unset"="Unset"; +"update.firmware"="Update Your Firmware"; +"update.interval"="Update Interval"; +"user"="User"; +"user.details"="User Details"; +"voltage"="Voltage"; +"waiting"="Waiting. . ."; From 688f7f6b4c0dba771e09955d15e2f9bb15fd0223 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Thu, 15 Feb 2024 20:19:39 -0800 Subject: [PATCH 10/10] Translated strings --- he.lproj/Localizable.strings | 615 ++++++++++++++++++----------------- 1 file changed, 308 insertions(+), 307 deletions(-) diff --git a/he.lproj/Localizable.strings b/he.lproj/Localizable.strings index 707334a0..f84e47a6 100644 --- a/he.lproj/Localizable.strings +++ b/he.lproj/Localizable.strings @@ -5,310 +5,311 @@ Copyright(c) Garth Vander Houwen on 12/12/22. */ -"about"="About"; -"about.meshtastic"="About Meshtastic"; -"admin"="Admin"; -"admin.log"="Admin Message Log"; -"ago"="ago"; -"airtime"="Airtime"; -"always.on"="Always On"; -"ambient.lighting"="Ambient Lighting"; -"ambient.lighting.config"="Ambient Lighting Config"; -"appsettings"="App Settings"; -"appsettings.provide.location"="Share location"; -"appsettings.smartposition"="Smart Position"; -"are.you.sure"="Are you sure?"; -"ascii.capable"="ASCII Capable"; -"available.radios"="Available Radios"; -"automatic.detection"="Automatic Detection"; -"battery.level"="Battery Level"; -"ble.name"="BLE Name"; -"ble.connection.timeout %d %@"="Connection failed after %d attempts to connect to %@. You may need to forget your device under Settings > Bluetooth."; -"ble.errorcode.6 %@"="%@ The app will automatically reconnect to the preferred radio if it comes back in range."; -"ble.errorcode.14 %@"="%@ This error usually cannot be fixed without forgetting the device unders Settings > Bluetooth and re-connecting to the radio."; -"ble.errorcode.pin %@"="%@ Please try connecting again and check the PIN carefully."; -"bluetooth"="Bluetooth"; -"bluetooth.off"="Bluetooth is off"; -"bluetooth.config"="Bluetooth Config"; -"bluetooth.mode.randompin"="Random PIN"; -"bluetooth.mode.fixedpin"="Fixed PIN"; -"bluetooth.mode.nopin"="No PIN (Just Works)"; -"bluetooth.pairingmode"="Pairing Mode"; -"bluetooth.pin.validation"="BLE Pin must be 6 digits long."; -"bytes"="Bytes"; -"cancel"="Cancel"; -"canned.messages"="Canned Messages"; -"canned.messages.config"="Canned Messages Config"; -"canned.messages.preset.manual"="Manual Configuration"; -"canned.messages.preset.rakrotary"="RAK Rotary Encoder Module"; -"canned.messages.preset.cardkb"="M5 Stack Card KB / RAK Keypad"; -"channel"="Channel"; -"channel.role.disabled"="Disabled"; -"channel.role.primary"="Primary"; -"channel.role.secondary"="Secondary"; -"channel.utilization"="Channel Utilization"; -"channels"="Channels"; -"clear.app.data"="Clear App Data"; -"clear.log"="Clear"; -"close"="Close"; -"config.save.confirm"="After config values save the node will reboot."; -"communicating"="Communicating with device. ."; -"connected.radio"="Connected Radio"; -"connected"="Bluetooth Connected"; -"connecting"="Connecting . ."; -"contacts"="Contacts"; -"contacts %@"="Contacts (%@)"; -"copy"="Copy"; -"current"="Current"; -"default"="Default"; -"delete"="Delete"; -"detection.sensor"="Detection Sensor"; -"detection.sensor.config"="Detection Sensor Config"; -"detection.sensor.log"="Detection Sensor Log"; -"device"="Device"; -"device.config"="Device Config"; -"device.metrics.delete"="Delete all device metrics?"; -"device.metrics.log"="Device Metrics Log"; -"device.role.client"="App connected or stand alone messaging device."; -"device.role.clientmute"="Device that does not forward packets from other devices."; -"device.role.clienthidden"="Device that only broadcasts as needed for stealth or power savings."; -"device.role.tracker"="Broadcasts GPS position packets as priority."; -"device.role.lostandfound"="Broadcasts location as message to default channel regularly for to assist with device recovery."; -"device.role.sensor"="Broadcasts telemetry packets as priority."; -"device.role.tak"="Optimized for ATAK system communication, reduces routine broadcasts."; -"device.role.repeater"="Infrastructure node for extending network coverage by relaying messages with minimal overhead. Not visible in Nodes list."; -"device.role.router"="Infrastructure node for extending network coverage by relaying messages. Visible in Nodes list."; -"device.role.routerclient"="Combination of both ROUTER and CLIENT. Not for mobile devices."; -"direct.messages"="Direct Messages"; -"dismiss.keyboard"="Dismiss"; -"display"="Display (Device Screen)"; -"display.config"="Display Config"; -"distance"="Distance"; -"disconnect"="Disconnect"; -"echo"="Echo"; -"email.address"="Email Address"; -"enabled"="Enabled"; -"encrypted"="Encrypted"; -"external.notification"="External Notification"; -"external.notification.config"="External Notification Config"; -"finish"="Finish"; -"firmware.version"="Firmware Version"; -"firmware.version.unsupported"="Unsupported Firmware Version Detected, unable to connect to device."; -"gas"="Gas"; -"gas.resistance"="Gas Resistance"; -"generate.qr.code"="Generate QR Code"; -"gpsformat.dec"="Decimal Degrees Format"; -"gpsformat.dms"="Degrees Minutes Seconds"; -"gpsformat.utm"="Universal Transverse Mercator"; -"gpsformat.mgrs"="Military Grid Reference System"; -"gpsformat.olc"="Open Location Code (aka Plus Codes)"; -"gpsformat.osgr"="Ordnance Survey Grid Reference"; -"gpsmode.disabled"="Disabled"; -"gpsmode.enabled"="Enabled"; -"gpsmode.notPresent"="Not Present"; -"heard"="Heard"; -"heard.last"="Last Heard"; -"hybrid"="Hybrid"; -"hybrid.flyover"="Hybrid Flyover"; -"include"="Include"; -"inputevent.none"="None"; -"inputevent.up"="Up"; -"inputevent.down"="Down"; -"inputevent.left"="Left"; -"inputevent.right"="Right"; -"inputevent.select"="Select"; -"inputevent.back"="Back"; -"inputevent.cancel"="Cancel"; -"interval.one.second"="One Second"; -"interval.two.seconds"="Two Seconds"; -"interval.three.seconds"="Three Seconds"; -"interval.four.seconds"="Four Seconds"; -"interval.five.seconds"="Five Seconds"; -"interval.ten.seconds"="Ten Seconds"; -"interval.fifteen.seconds"="Fifteen Seconds"; -"interval.twenty.seconds"="Twenty Seconds"; -"interval.twentyfive.seconds"="Twenty Five Seconds"; -"interval.thirty.seconds"="Thirty Seconds"; -"interval.fortyfive.seconds"="Forty Five Seconds"; -"interval.one.minute"="One Minute"; -"interval.two.minutes"="Two Minutes"; -"interval.five.minutes"="Five Minutes"; -"interval.ten.minutes"="Ten Minutes"; -"interval.fifteen.minutes"="Fifteen Minutes"; -"interval.thirty.minutes"="Thirty Minutes"; -"interval.one.hour"="One Hour"; -"interval.two.hours"="Two Hours"; -"interval.three.hours"="Three Hours"; -"interval.four.hours"="Four Hours"; -"interval.five.hours"="Five Hours"; -"interval.six.hours"="Six Hours"; -"interval.twelve.hours"="Twelve Hours"; -"interval.eighteen.hours"="Eighteen Hours"; -"interval.twentyfour.hours"="Twenty Four Hours"; -"interval.thirtysix.hours"="Thirty Six Hours"; -"interval.fortyeight.hours"="Forty Eight Hours"; -"interval.seventytwo.hours"="Seventy Two Hours"; -"keyboard.type"="Keyboard Type"; -"logging"="Logging"; -"lora"="LoRa"; -"lora.config"="LoRa Config"; -"map"="Mesh Map"; -"map.type"="Default Type"; -"map.centering"="Centering Mode"; -"map.tiles.delete"="Delete All Map Tiles"; -"map.recentering"="Automatic Re-centering"; -"map.use.legacy"="Use Legacy Mesh Map"; -"map.usertrackingmode"="User tracking mode"; -"map.usertrackingmode.follow"="Follow"; -"map.usertrackingmode.followwithheading"="Follow with heading"; -"map.usertrackingmode.none"="None"; -"mesh.live.activity"="Mesh Live Activity"; -"mesh.log"="Mesh Log"; -"mesh.log.ambientlighting.config %@"="Ambient Lighting module config received: %@"; -"mesh.log.bluetooth.config %@"="Bluetooth config received: %@"; -"mesh.log.cannedmessage.config %@"="Canned Message module config received: %@"; -"mesh.log.cannedmessages.messages.get %@"="Requested Canned Messages Module Messages for node: %@"; -"mesh.log.cannedmessages.messages.received %@"="Canned Messages Messages Received For: %@"; -"mesh.log.channel.sent %@ %d"="Sent a Channel for: %@ Channel Index %d"; -"mesh.log.channel.received %d %@"="Channel %d received from: %@"; -"mesh.log.device.config %@"="Device config received: %@"; -"mesh.log.display.config %@"="Display config received: %@"; -"mesh.log.devicemetadata %@"="Requesting Device Metadata for %@"; -"mesh.log.device.metadata.received %@"="Device Metadata received from: %@"; -"mesh.log.detectionsensor.config %@"="Detection Sensor module config received: %@"; -"mesh.log.externalnotification.config %@"="External Notification module config received: %@"; -"mesh.log.lora.config %@"="LoRa config received: %@"; -"mesh.log.lora.config.sent %@"="Sent a LoRa.Config for: %@"; -"mesh.log.mqtt.config %@"="MQTT module config received: %@"; -"mesh.log.myinfo %@"="MyInfo received: %@"; -"mesh.log.network.config %@"="Network config received: %@"; -"mesh.log.nodeinfo.received %@"="Node info received for: %@"; -"mesh.log.position.config %@"="Positon config received: %@"; -"mesh.log.position.received %@"="Position Packet received from node: %@"; -"mesh.log.rangetest.config %@"="Range Test module config received: %@"; -"mesh.log.ringtone.config %@"="RTTTL Ringtone config received: %@"; -"mesh.log.routing.message %@ %@"="Routing received for RequestID: %@ Ack Status: %@"; -"mesh.log.serial.config %@"="Serial module config received: %@"; -"mesh.log.sharelocation %@"="Sent a Position Packet from the Apple device GPS to node: %@"; -"mesh.log.storeforward.config %@"="Store & Forward module config received: %@"; -"mesh.log.telemetry.config %@"="Telemetry module config received: %@"; -"mesh.log.telemetry.received %@"="Telemetry received for: %@"; -"mesh.log.textmessage.received"="Message received from the text message app."; -"mesh.log.textmessage.send.failed %@"="Message Send Failed, not properly connected to %@"; -"mesh.log.textmessage.sent %@ %@ %@"="Sent message %@ from %@ to %@"; -"mesh.log.traceroute.received.direct %@"="Trace Route request sent to node: %@ was recieived directly."; -"mesh.log.traceroute.received.route %@"="Trace Route request returned: %@"; -"mesh.log.traceroute.sent %@"="Sent a Trace Route Request to node: %@"; -"mesh.log.wantconfig %@"="Issuing Want Config to %@"; -"mesh.log.waypoint.sent %@"="Sent a Waypoint Packet from: %@"; -"mesh.log.waypoint.received %@"="Waypoint Packet received from node: %@"; -"message"="Message"; -"message.details"="Message Details"; -"messages"="Messages"; -"mode"="Mode"; -"module.configuration"="Module Configuration"; -"mqtt"="MQTT"; -"mqtt.connect"="Connect to MQTT"; -"mqtt.config"="MQTT Config"; -"mqtt.clientproxy"="MQTT Client Proxy"; -"mqtt.disconnect"="Disconnect from MQTT"; -"mqtt.username"="Username"; -"name"="Name"; -"network"="Network"; -"network.config"="Network Config"; -"nodes"="Nodes"; -"nodes %@"="Nodes (%@)"; -"no.nodes"="No Meshtastic Nodes Found"; -"not.connected"="No device connected"; -"numbers.punctuation"="Numbers and Punctuation"; -"off"="Off"; -"offline"="Offline"; -"on.boot"="On Boot Only"; -"options"="Options"; -"password"="Password"; -"pause"="Pause"; -"phone.gps"="Phone GPS"; -"phone.gps.interval.description"="How frequently your phone will send your location to the device, location updates to the mesh are managed by the device."; -"position"="Position"; -"position.config"="Position Config"; -"preferred.radio"="Preferred Radio"; -"radio.configuration"="Radio Configuration"; -"range.test"="Range Test"; -"range.test.blocked"="Block Range Test"; -"range.test.config"="Range Test Config"; -"reply"="Reply"; -"reboot"="Reboot"; -"reboot.node"="Reboot node?"; -"received.ack"="Received Ack"; -"received.ack.real"="Recipient Ack"; -"resume"="Resume"; -"ringtone"="Ringtone"; -"ringtone.config"="Ringtone Config"; -"route.recorder"="Route Recorder"; -"routes"="Routes"; -"routing.acknowledged"="Acknowledged"; -"routing.noroute"="No Route"; -"routing.gotnak"="Received a negative acknowledgment"; -"routing.timeout"="Timeout"; -"routing.nointerface"="No Interface"; -"routing.maxretransmit"="Max Retransmission Reached"; -"routing.nochannel"="No Channel"; -"routing.toolarge"="The packet is too large"; -"routing.noresponse"="No Response"; -"routing.dutycyclelimit"="Regional Duty Cycle Limit Reached"; -"routing.badRequest"="Bad Request"; -"routing.notauthorized"="Not Authorized"; -"satellite"="Satellite"; -"satellite.flyover"="Satellite Flyover"; -"save"="Save"; -"save.config %@"="Save Config for %@"; -"serial"="Serial"; -"serial.config"="Serial Config"; -"serial.mode.default"="Default"; -"serial.mode.simple"="Simple"; -"serial.mode.proto"="Protobufs"; -"serial.mode.txtmsg"="Text Message"; -"serial.mode.nmea"="NMEA Positions"; -"settings"="Settings"; -"share.channels"="Share Channels QR Code"; -"share.position"="Share Position"; -"subscribed"="Subscribed to mesh"; -"select.contact"="Select a Contact"; -"select.node"="Select a Node"; -"select.menu.item"="Select an item from the menu"; -"set.region"="Set LoRa Region"; -"standard"="Standard"; -"standard.muted"="Standard Muted"; -"start"="Start"; -"storeforward"="Store & Forward"; -"storeforward.config"="Store & Forward Config"; -"storeforward.heartbeat"="Send Heartbeat"; -"ssid"="SSID"; -"tapback"="Tapback Response"; -"tapback.heart"="Heart"; -"tapback.thumbsup"="Thumbs Up"; -"tapback.thumbsdown"="Thumbs Down"; -"tapback.haha"="HaHa"; -"tapback.exclamation"="Exclamation Mark"; -"tapback.question"="Question Mark"; -"tapback.poop"="Poop"; -"telemetry"="Telemetry (Sensors)"; -"telemetry.config"="Telemetry Config"; -"timeout"="Timeout"; -"timestamp"="Timestamp"; -"tip.bluetooth.connect.title"="Connected Radio"; -"tip.bluetooth.connect.message"="Shows information for the Lora radio currently connected via bluetooth. You can swipe left to disconnect the radio and long press to view stats or start the live activity."; -"tip.channels.share.title"="Sharing Meshtastic Channels"; -"tip.channels.share.message"="In a Meshtastic LoRa Mesh there are up to 8 channels. The first one is the Primary channel where most activity happens and is required. If you don't share your primary channel your first shared channel becomes the primary channel on the other network. It talks on its primary and your secondary channel. A channel with the name 'admin' controls nodes remotely. Other channels are for private groups, each with its own key."; -"tip.messages.title"="Messages"; -"tip.messages.message"="You can send and receive channel (group chats) and direct messages. From any message you can long press to see available actions like copy, reply, tapback and delete as well as delivery details."; -"twitter"="Twitter"; -"unknown"="Unknown"; -"unknown.age"="Unknown Age"; -"unset"="Unset"; -"update.firmware"="Update Your Firmware"; -"update.interval"="Update Interval"; -"user"="User"; -"user.details"="User Details"; -"voltage"="Voltage"; -"waiting"="Waiting. . ."; +"about"="אודות"; +"about.meshtastic"="אודות משטסטיק"; +"admin"="אדמין"; +"admin.log"="היסטוריית הודעות אדמין"; +"ago"="עברו"; +"airtime"="זמן אוויר"; +"always.on"="תמיד דלוק"; +"ambient.lighting"="תאורת סביבה"; +"ambient.lighting.config"="הגדרות תאורת סביבה"; +"appsettings"="הגדרות אפליקציה"; +"appsettings.provide.location"="שתף מיקום"; +"appsettings.smartposition"="מיקום חכם"; +"are.you.sure"="האם אתה בטוח?"; +"ascii.capable"="בעל יכולת ASCII"; +"available.radios"="מכשירים זמינים"; +"automatic.detection"="זיהוי אוטומטי"; +"battery.level"="רמת סוללה"; +"ble.name"="שם בלוטוס"; +"ble.connection.timeout %d %@"="התחברות נכשלה לאחר %d נסיונות להתחבר ל%@. יתכן ויש צורך 'לשכוח' את המכשיר בהגדרות מכשיר > בלוטוס."; +"ble.errorcode.6 %@"="%@ האפליקציה תנסה אוטומטית להתחבר מחדש למכשיר המועדף אם ייראה."; +"ble.errorcode.14 %@"="%@ שגיאה זו בדרך כלל אינה ניתנת לתיקון ללא שכחחת המכשיר בהגדרות מכשיר > בלוטוס ואז להתחבר מחדש למכשיר."; +"ble.errorcode.pin %@"="%@ בבקשה נסה שנית להתחבר למכשיר ובדוק את הקוד."; +"bluetooth"="בלוטוס"; +"bluetooth.off"="בלוטוס כבוי"; +"bluetooth.config"="הגדרות בלוטוס"; +"bluetooth.mode.randompin"="קוד אקראי"; +"bluetooth.mode.fixedpin"="קוד קבוע"; +"bluetooth.mode.nopin"="ללא קוד (פשוט עובד)"; +"bluetooth.pairingmode"="מצב הצמדה"; +"bluetooth.pin.validation"="קוד בלוטוס חייבת להיות בת 6 ספרות."; +"bytes"="בייטים"; +"cancel"="בטל"; +"canned.messages"="הודעות קבועות"; +"canned.messages.config"="הגדרות הודעות קבועות"; +"canned.messages.preset.manual"="הגדרה ידנית"; +"canned.messages.preset.rakrotary"="RAK Rotary Encoder Module"; /* left untranslated for clarity */ +"canned.messages.preset.cardkb"="M5 Stack Card KB / RAK Keypad"; /* left untranslated for clarity */ +"channel"="ערוץ"; +"channel.role.disabled"="כבוי"; +"channel.role.primary"="עיקרי"; +"channel.role.secondary"="משני"; +"channel.utilization"="שימוש ערוץ"; +"channels"="ערוצים"; +"clear.app.data"="אפס הגדרות אפליקציה"; +"clear.log"="נקה"; +"close"="סגור"; +"config.save.confirm"="לאחר שמירת הגדרות המכשיר יתחיל מחדש."; +"communicating"="מתקשר עם מכשיר. ."; +"connected.radio"="מכשיר מחובר"; +"connected"="מחובר בבלוטוס"; +"connecting"="מתחבר . ."; +"contacts"="אנשי קשר"; +"contacts %@"="אנשי קשר (%@)"; +"copy"="העתק"; +"current"="נוכחי"; +"default"="ברירת מחדל"; +"delete"="מחק"; +"detection.sensor"="חיישן זיהוי"; +"detection.sensor.config"="הגדרות חיישן זיהוי"; +"detection.sensor.log"="יומן חיישן זיהוי"; +"device"="מכשיר"; +"device.config"="הגדרות מכשיר"; +"device.metrics.delete"="נקה יומן מכשיר?"; +"device.metrics.log"="יומן מכשיר"; +"device.role.client"="אפליקציה מחוברת או מכשיר תקשורת עצמאי."; +"device.role.clientmute"="מכשיר שאינו מעביר הודעות ממכשירים אחרים הלאה."; +"device.role.clienthidden"="מכשיר שרק משדר לפי צורך בכדי לחסוך בחשמל או לשמור על חשאיות."; +"device.role.tracker"="משדר מיקום GPS בעדיפות גבוהה."; +"device.role.lostandfound"="משדר מיקום כהודעה לערוץ ברירת מחדל לעיתים קבועות בכדי לסייע במציאת המכשיר."; +"device.role.sensor"="משדר טלמטריה בעדיפות גבוהה."; +"device.role.tak"="מותאם למערכת ATAK, מקטין תקשורת קבועה."; +"device.role.repeater"="מכשיר תשתית להרחבת המש על ידי העברת הודעות עם דאטה נוסף מינימלי."; +"device.role.router"="מכשיר תשתית להרחבת המש על ידי העברת הודעות. מופיע ברשימת מכשירים."; +"device.role.routerclient"="קומבינציה של ROUTER וCLIENT. לא למכשירים ניידים."; +"direct.messages"="הודעה פרטית"; +"dismiss.keyboard"="סגור מקלדת"; +"display"="צג מכשיר"; +"display.config"="הגדרות צג"; +"distance"="מרחק"; +"disconnect"="התנתק"; +"echo"="הד"; +"email.address"="כתובת דואר אלקטרוני"; +"enabled"="מופעל"; +"encrypted"="מוצפן"; +"external.notification"="נוטיפיקציה חיצונית"; +"external.notification.config"="הגדרות נוטיפיקציה חיצונית"; +"finish"="סיים"; +"firmware.version"="גרסת קושחה"; +"firmware.version.unsupported"="גרסת קושחה אינה נתמכת, לא ניתן להתחבר למכשיר."; +"gas"="דלק"; +"gas.resistance"="Gas Resistance"; /* left untranslated for clarity */ +"generate.qr.code"="צור קוד QR"; +"gpsformat.dec"="פורמט קואורדינטות"; +"gpsformat.dms"="מעלות דקות שניות"; +"gpsformat.utm"="Universal Transverse Mercator"; /* left untranslated for clarity. A translation exists but is frankly indecipherable */ +"gpsformat.mgrs"="Military Grid Reference System"; /* left untranslated for clarity. A translation exists but is frankly indecipherable */ +"gpsformat.olc"="Open Location Code (aka Plus Codes)"; /* left untranslated for clarity. A translation exists but is frankly indecipherable */ +"gpsformat.osgr"="Ordnance Survey Grid Reference"; /* left untranslated for clarity. A translation exists but is frankly indecipherable */ +"gpsmode.disabled"="כבוי"; +"gpsmode.enabled"="מופעל"; +"gpsmode.notPresent"="לא קיים"; +"heard"="נשמע"; +"heard.last"="נשמע לאחרונה"; +"hybrid"="היברידי"; +"hybrid.flyover"="היברידי מלמעלה"; +"include"="כלול"; +"inputevent.none"="ללא"; +"inputevent.up"="למעלה"; +"inputevent.down"="למטה"; +"inputevent.left"="שמאלה"; +"inputevent.right"="ימינה"; +"inputevent.select"="בחר"; +"inputevent.back"="אחרוה"; +"inputevent.cancel"="בטל"; +"interval.one.second"="שניה אחת"; +"interval.two.seconds"="שתי שניות"; +"interval.three.seconds"="שלוש שניות"; +"interval.four.seconds"="ארבע שניות"; +"interval.five.seconds"="חמש שניות"; +"interval.ten.seconds"="עשר שניות"; +"interval.fifteen.seconds"="חמש עשרה שניות"; +"interval.twenty.seconds"="עשרים שניות"; +"interval.twentyfive.seconds"="עשרים וחמש שניות"; +"interval.thirty.seconds"="שלושים שניות"; +"interval.fortyfive.seconds"="ארבעים וחמש שניות"; +"interval.one.minute"="דקה אחת"; +"interval.two.minutes"="שתי דקות"; +"interval.five.minutes"="חמש דקות"; +"interval.ten.minutes"="עשר דקות"; +"interval.fifteen.minutes"="חמש עשרה דקות"; +"interval.thirty.minutes"="שלושים דקות"; +"interval.one.hour"="שעה אחת"; +"interval.two.hours"="שעתיים"; +"interval.three.hours"="שלוש שעות"; +"interval.four.hours"="ארבע שעות"; +"interval.five.hours"="חמש שעות"; +"interval.six.hours"="שש שעות"; +"interval.twelve.hours"="שניים עשר שעות"; +"interval.eighteen.hours"="שמונה עשר שעות"; +"interval.twentyfour.hours"="עשרים וארבע שעות"; +"interval.thirtysix.hours"="שלושים ושש שעות"; +"interval.fortyeight.hours"="ארבעים ושמונה שעות"; +"interval.seventytwo.hours"="שבעים ושתיים שעות"; +"keyboard.type"="סוג מקלדת"; +"logging"="רישום"; +"lora"="לורה"; +"lora.config"="הגדרות לורה"; +"map"="מפת מש"; +"map.type"="סוג ברירת מחדל"; +"map.centering"="מכשיר במרכז"; +"map.tiles.delete"="מחק כל חלקי מפה שמורים"; +"map.recentering"="מרכז מפה אוטומטית"; +"map.use.legacy"="השתמש במפה מדור קודם"; +"map.usertrackingmode"="מצב מעקב אחר משתמש"; +"map.usertrackingmode.follow"="עקוב"; +"map.usertrackingmode.followwithheading"="עקוב עם כיוון"; +"map.usertrackingmode.none"="ללא"; +"mesh.live.activity"="פעילות מש חיה"; +"mesh.log"="יומן מש"; +"mesh.log.ambientlighting.config %@"="הגדרות מודולת תאורת סביבה התקבלו: %@"; +"mesh.log.bluetooth.config %@"="הגדרות בלוטוס התקבלו: %@"; +"mesh.log.cannedmessage.config %@"="הגדרות מודולת תגובות שמורות התקבלו: %@"; +"mesh.log.cannedmessages.messages.get %@"="התבקשו הודעות מודולת הודעות שמורות עבור מכשיר: %@"; +"mesh.log.cannedmessages.messages.received %@"="הודעות עבור הודעות שמורות התקבלו מ-%@"; +"mesh.log.channel.sent %@ %d"="נשלח ערוץ עבור: %@ אינדקס ערוצים %d"; +"mesh.log.channel.received %d %@"="ערוץ %d התקבל מ-%@"; +"mesh.log.device.config %@"="הגדרות מכשיר התקבלו: %@"; +"mesh.log.display.config %@"="הגדרות תצוגה התקבלו: %@"; +"mesh.log.devicemetadata %@"="מבקש מטא-דאטה עבור %@"; +"mesh.log.device.metadata.received %@"="מטא-דאטה של מכשיר התקבל מ-%@"; +"mesh.log.detectionsensor.config %@"="הגדרות מודולת חיישן זיהוי התקבלו: %@"; +"mesh.log.externalnotification.config %@"="הגדרות מודולת נוטיפיקציה חיצונית התקבלו: %@"; +"mesh.log.lora.config %@"="הגדרות לורה התקבלו: %@"; +"mesh.log.lora.config.sent %@"="נשלחו הגדרות לורה עבור: %@"; +"mesh.log.mqtt.config %@"="הגדרות מודולת MQTT התקבלו: %@"; +"mesh.log.myinfo %@"="MyInfo התקבל: %@"; +"mesh.log.network.config %@"="הגדרות רשת התקבלו: %@"; +"mesh.log.nodeinfo.received %@"="מידע אודות מכשיר התקבל: %@"; +"mesh.log.position.config %@"="הגדרות מיקום התקבלו: %@"; +"mesh.log.position.received %@"="הודעת מיקום התקבלו מ-%@"; +"mesh.log.rangetest.config %@"="הגדרות מודולת בדיקת טווח התקבלו: %@"; +"mesh.log.ringtone.config %@"="הגדרות RTTTL רינגטון התקבלו: %@"; +"mesh.log.routing.message %@ %@"="התקבל מסלול עבור בקשה: %@ מצב שליחה: %@"; +"mesh.log.serial.config %@"="הגדרות מודולת תקשורת סיריאלית התקבלו: %@"; +"mesh.log.sharelocation %@"="נשלח מיקום ממכשיר האפל למכשיר המשטסטיק: %@"; +"mesh.log.storeforward.config %@"="הגדרות מודולת שמירה ושליחה התקבלו: %@"; +"mesh.log.telemetry.config %@"="הגדרות מודולת טלמטריה התקבלו: %@"; +"mesh.log.telemetry.received %@"="התקבל טלמטריה עבור: %@"; +"mesh.log.textmessage.received"="הודעת טקסט התקבלה."; +"mesh.log.textmessage.send.failed %@"="שליחת הודעה נכשלה, אין חיבוריות ל-%@"; +"mesh.log.textmessage.sent %@ %@ %@"="נשלחה הודעה %@ מ-%@ ל-%@"; +"mesh.log.traceroute.received.direct %@"="בקשת בדיקת מסלול נשלחה למכשיר: %@ התקבל ישירות."; +"mesh.log.traceroute.received.route %@"="בקשת בדיקת מסלול הצליחה: %@"; +"mesh.log.traceroute.sent %@"="נשלחה בקשת בדיקת מסלול למכשיר: %@"; +"mesh.log.wantconfig %@"="שולח בקשת הגדרות ל-%@"; +"mesh.log.waypoint.sent %@"="נשלחה נקודת ציון מ-%@"; +"mesh.log.waypoint.received %@"="נקודת ציון התקבלה מ-%@"; +"message"="הודעה"; +"message.details"="פרטי הודעה"; +"messages"="הודעות"; +"mode"="מצב"; +"module.configuration"="הגדרות מודולה"; +"mqtt"="MQTT"; /*left untranslated for clarity */ +"mqtt.connect"="התחבר ל-MQTT"; +"mqtt.config"="הגדרות MQTT"; +"mqtt.clientproxy"="MQTT Client Proxy"; /*left untranslated for clarity */ +"mqtt.disconnect"="התנתק מ-MQTT"; +"mqtt.username"="שם משתמש"; +"name"="שם"; +"network"="רשת"; +"network.config"="הגדרות רשת"; +"nodes"="מכשירים"; +"nodes %@"="מכשירים (%@)"; +"no.nodes"="לא נמצאו מכשירי משטסטיק"; +"not.connected"="אין מכשיר מחובר"; +"numbers.punctuation"="מספרים וסימני פיסוק "; +"off"="כבוי"; +"offline"="מנותק"; +"on.boot"="רק בעת הדלקה"; +"options"="הגדרות"; +"password"="סיסמא"; +"pause"="הפסק"; +"phone.gps"="GPS מהטלפון"; +"phone.gps.interval.description"="כל כמה זמן מכשיר הטלפון ישלח את מיקומך למכשיר המשטסטיק. עדכוני מיקום למש מנוהלות על ידי המכשיר."; +"position"="מיקום"; +"position.config"="הגדרות מיקום"; +"preferred.radio"="רדיו מועדף"; +"radio.configuration"="הגדרות רדיו"; +"range.test"="בדיקת טווח"; +"range.test.blocked"="חסום בדיקות טווח"; +"range.test.config"="הגדרות בדיקת טווח"; +"reply"="תגובה"; +"reboot"="התחל מחדש"; +"reboot.node"="התחל מכשיר מחדש??"; +"received.ack"="התקבל אישור מסירה"; +"received.ack.real"="התקבל אישור מסירה מהנמען"; +"resume"="החל מחדש"; +"ringtone"="רינגטון"; +"ringtone.config"="הגדרות רינגטון"; +"route.recorder"="מקליט מסלול"; +"routes"="מסלולים"; +"routing.acknowledged"="מאשר"; +"routing.noroute"="אין מסלול"; +"routing.gotnak"="התקבל אישור מסירה שלילי"; +"routing.timeout"="נגמר הזמן"; +"routing.nointerface"="אין ממשק"; +"routing.maxretransmit"="הגיע למקסימום השליחות מדש"; +"routing.nochannel"="אין ערוץ"; +"routing.toolarge"="ההודעה ארוכה/גדולה מידי"; +"routing.noresponse"="אין תגובה"; +"routing.dutycyclelimit"="הגיע למקסימום שימוש אזורי לשעה זו"; +"routing.badRequest"="בקשה לא תקינה"; +"routing.notauthorized"="לא מאושר"; +"satellite"="לווין"; +"satellite.flyover"="לווין בשמיים"; +"save"="שמור"; +"save.config %@"="שמור הגדרות עבור %@"; +"serial"="סיריאלי"; +"serial.config"="'הגדרות מודולה 'סיריאלי"; +"serial.mode.default"="ברירת מחדל"; +"serial.mode.simple"="פשוט"; +"serial.mode.proto"="Protobufs"; /*left untranslated for clarity */ +"serial.mode.txtmsg"="הודעת טקסט"; +"serial.mode.nmea"="מיקומי NMEA"; +"settings"="הגדרות"; +"share.channels"="שתף ערוצים באמצעות קוד QR"; +"share.position"="שתף מיקום"; +"subscribed"="מחובר למש"; +"select.contact"="בחר איש קשר"; +"select.node"="בחר מכשיר"; +"select.menu.item"="בחר מהתפריט"; +"set.region"="בחר אזור לורה"; +"standard"="סטנדרטי"; +"standard.muted"="סטנדרתי-השתק"; +"start"="החל"; +"storeforward"="שמירה ושליחה"; +"storeforward.config"="הגדרות שמירה ושליחה"; +"storeforward.heartbeat"="שלח דופק"; +"ssid"="שם רשת וויפי"; +"tapback"="תגובה מהירה"; +"tapback.heart"="לב"; +"tapback.thumbsup"="אגודל למעלה"; +"tapback.thumbsdown"="אגודל למטה"; +"tapback.haha"="חחח"; +"tapback.exclamation"="סימן קריאה"; +"tapback.question"="סימן שאלה"; +"tapback.poop"="חרא"; +"telemetry"="טלמטריה (חיישנים)"; +"telemetry.config"="הגדרות טלמטריה"; +"timeout"="זמן קצוב"; +"timestamp"="שעה/תאריך"; +"tip.bluetooth.connect.title"="מכשיר מחובר"; +מראה מידע אודות מכשיר המשטסטיק המחובר כעת לבלוטוס. ניתן לגרור שמאלה להתנתקות או לחיצה ארוכה לראות סטטיסטיקה או להתחיל פעילות. +"tip.bluetooth.connect.message"="מראה מידע אודות מכשיר המשטסטיק המחובר כעת לבלוטוס. ניתן לגרור שמאלה להתנתקות או לחיצה ארוכה לראות סטטיסטיקה או להתחיל פעילות."; +"tip.channels.share.title"="משתף ערוצי משטסטיק"; +"tip.channels.share.message"="במשטסטיק יש עד 8 ערוצים. הראשון הינו הראשי והינו היכן שרוב הפעילות מתבצעת והכרחי. אם לא תשתף את הערוץ הראשי שלך הערוץ הראשון שלך נהיה הערוץ הראשי ברשת השניה. הוא מדבר בערוץ הראשי שלו במשני שלך. ערוץ בעל השם 'admin' הינו לשליטה מרחוק. ערוצים נוספים הינם לקבוצות פרטיות, כל אחת עם מפתח הצפנה משלה."; +"tip.messages.title"="הודעות"; +"tip.messages.message"="ניתן לשלוח הודעות ערוץ (קבוצות צ'אט) והודעות פרטיות. על הודעה ניתן לעשות לחיצה ארוכה בכדי לראות פעולות אפשריות כגון העתק, הגב, תגובה מהירה, מחק ובנוסף לראות מצב שליחה."; +"twitter"="טוויטר"; +"unknown"="לא ידוע"; +"unknown.age"="גיל לא ידוע"; +"unset"="לא נקבע"; +"update.firmware"="עדכן קושחה"; +"update.interval"="זמן בין עדכונים"; +"user"="משתמש"; +"user.details"="פרטי משתמש"; +"voltage"="וולטז'"; +"waiting"="ממתין. . .";