From b60a9eb66ea3c88ccbb537e1d87717cb8fcf4f44 Mon Sep 17 00:00:00 2001 From: Taksh Date: Sun, 9 Aug 2026 13:16:49 +0000 Subject: [PATCH 1/3] feat: summarize mesh bridge status in settings the bridge settings card only exposed a toggle and a no-cell caption, so the active rendezvous cell, how many people are reachable via the bridge, and whether composing stays nearby-only all had to be inferred from the header icons. add a BridgeStatusSummary formatter and render it as a one-line status under the toggle. --- .../Gateway/BridgeStatusSummary.swift | 63 +++++++++++++++++++ bitchat/Views/AppInfoView.swift | 19 ++++++ 2 files changed, 82 insertions(+) create mode 100644 bitchat/Services/Gateway/BridgeStatusSummary.swift diff --git a/bitchat/Services/Gateway/BridgeStatusSummary.swift b/bitchat/Services/Gateway/BridgeStatusSummary.swift new file mode 100644 index 00000000..3737fe4c --- /dev/null +++ b/bitchat/Services/Gateway/BridgeStatusSummary.swift @@ -0,0 +1,63 @@ +// +// BridgeStatusSummary.swift +// bitchat +// +// This is free and unencumbered software released into the public domain. +// For more information, see +// + +import Foundation + +/// One-line mesh bridge status for the settings pane. +enum BridgeStatusSummary { + static func formatted( + enabled: Bool, + cell: String?, + bridgedCount: Int, + nearbyOnly: Bool + ) -> String { + if !enabled { + return String( + localized: "app_info.settings.bridge.status.off", + defaultValue: "bridge off — only radio-range mesh traffic", + comment: "Bridge status line when the mesh bridge toggle is off" + ) + } + let cellPart = cell.map { + String( + format: String( + localized: "app_info.settings.bridge.status.cell", + defaultValue: "rendezvous #%@", + comment: "Bridge status fragment showing rendezvous cell; %@ is geohash" + ), + locale: .current, + $0 + ) + } ?? String( + localized: "app_info.settings.bridge.status.no_cell", + defaultValue: "no rendezvous cell", + comment: "Bridge status fragment when no cell is active" + ) + let peoplePart = String( + format: String( + localized: "app_info.settings.bridge.status.people", + defaultValue: "%lld people via bridge", + comment: "Bridge status fragment counting bridged participants; %lld is count" + ), + locale: .current, + bridgedCount + ) + let composePart = nearbyOnly + ? String( + localized: "app_info.settings.bridge.status.compose_nearby", + defaultValue: "compose: nearby only", + comment: "Bridge status fragment when outgoing mesh messages stay on radio" + ) + : String( + localized: "app_info.settings.bridge.status.compose_bridged", + defaultValue: "compose: bridged", + comment: "Bridge status fragment when outgoing mesh messages cross the bridge" + ) + return [cellPart, peoplePart, composePart].joined(separator: " · ") + } +} diff --git a/bitchat/Views/AppInfoView.swift b/bitchat/Views/AppInfoView.swift index cb99fbac..29d1aafe 100644 --- a/bitchat/Views/AppInfoView.swift +++ b/bitchat/Views/AppInfoView.swift @@ -78,6 +78,14 @@ struct AppInfoView: View { ) } static let bridgeNoCell = String(localized: "app_info.settings.bridge.no_cell", defaultValue: "no rendezvous cell yet — needs location access or a nearby bridge peer", comment: "Caption under the mesh bridge toggle when the bridge is on but has no geohash cell to meet on") + static func bridgeStatusSummary(enabled: Bool, cell: String?, bridgedCount: Int, nearbyOnly: Bool) -> String { + BridgeStatusSummary.formatted( + enabled: enabled, + cell: cell, + bridgedCount: bridgedCount, + nearbyOnly: nearbyOnly + ) + } // Moved from LocationChannelsSheet; keys unchanged. (The former // internet-gateway toggle is gone: the bridge switch drives all @@ -440,6 +448,17 @@ struct AppInfoView: View { .bitchatFont(size: 11) .foregroundColor(secondaryTextColor) } + Text( + verbatim: Strings.Settings.bridgeStatusSummary( + enabled: bridgeService.isEnabled, + cell: bridgeService.activeCell, + bridgedCount: bridgeService.bridgedPeerCount, + nearbyOnly: bridgeService.nearbyOnly + ) + ) + .bitchatFont(size: 11) + .foregroundColor(secondaryTextColor) + .fixedSize(horizontal: false, vertical: true) } settingsCard { From 0d4e37632e66c9e6404612f7645477dcc634aa6e Mon Sep 17 00:00:00 2001 From: Taksh Date: Sun, 9 Aug 2026 13:16:49 +0000 Subject: [PATCH 2/3] l10n: add bridge status strings six keys for the status line, english translated and the other locales seeded needs_review, matching how the rest of the catalog carries pending translations. --- bitchat/Localizable.xcstrings | 1116 +++++++++++++++++++++++++++++++++ 1 file changed, 1116 insertions(+) diff --git a/bitchat/Localizable.xcstrings b/bitchat/Localizable.xcstrings index f869ab85..329b05e6 100644 --- a/bitchat/Localizable.xcstrings +++ b/bitchat/Localizable.xcstrings @@ -13034,6 +13034,1122 @@ } } }, + "app_info.settings.bridge.status.cell" : { + "comment" : "Bridge status fragment showing rendezvous cell; %@ is geohash", + "extractionState" : "manual", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "rendezvous #%@" + } + }, + "bn" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "rendezvous #%@" + } + }, + "de" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "rendezvous #%@" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "rendezvous #%@" + } + }, + "es" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "rendezvous #%@" + } + }, + "fa" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "rendezvous #%@" + } + }, + "fil" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "rendezvous #%@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "rendezvous #%@" + } + }, + "he" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "rendezvous #%@" + } + }, + "hi" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "rendezvous #%@" + } + }, + "id" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "rendezvous #%@" + } + }, + "it" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "rendezvous #%@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "rendezvous #%@" + } + }, + "ko" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "rendezvous #%@" + } + }, + "ms" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "rendezvous #%@" + } + }, + "ne" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "rendezvous #%@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "rendezvous #%@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "rendezvous #%@" + } + }, + "pt" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "rendezvous #%@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "rendezvous #%@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "rendezvous #%@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "rendezvous #%@" + } + }, + "ta" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "rendezvous #%@" + } + }, + "th" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "rendezvous #%@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "rendezvous #%@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "rendezvous #%@" + } + }, + "ur" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "rendezvous #%@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "rendezvous #%@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "rendezvous #%@" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "rendezvous #%@" + } + } + } + }, + "app_info.settings.bridge.status.compose_bridged" : { + "comment" : "Bridge status fragment when outgoing mesh messages cross the bridge", + "extractionState" : "manual", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: bridged" + } + }, + "bn" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: bridged" + } + }, + "de" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: bridged" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "compose: bridged" + } + }, + "es" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: bridged" + } + }, + "fa" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: bridged" + } + }, + "fil" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: bridged" + } + }, + "fr" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: bridged" + } + }, + "he" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: bridged" + } + }, + "hi" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: bridged" + } + }, + "id" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: bridged" + } + }, + "it" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: bridged" + } + }, + "ja" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: bridged" + } + }, + "ko" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: bridged" + } + }, + "ms" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: bridged" + } + }, + "ne" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: bridged" + } + }, + "nl" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: bridged" + } + }, + "pl" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: bridged" + } + }, + "pt" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: bridged" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: bridged" + } + }, + "ru" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: bridged" + } + }, + "sv" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: bridged" + } + }, + "ta" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: bridged" + } + }, + "th" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: bridged" + } + }, + "tr" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: bridged" + } + }, + "uk" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: bridged" + } + }, + "ur" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: bridged" + } + }, + "vi" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: bridged" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: bridged" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: bridged" + } + } + } + }, + "app_info.settings.bridge.status.compose_nearby" : { + "comment" : "Bridge status fragment when outgoing mesh messages stay on radio", + "extractionState" : "manual", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: nearby only" + } + }, + "bn" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: nearby only" + } + }, + "de" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: nearby only" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "compose: nearby only" + } + }, + "es" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: nearby only" + } + }, + "fa" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: nearby only" + } + }, + "fil" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: nearby only" + } + }, + "fr" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: nearby only" + } + }, + "he" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: nearby only" + } + }, + "hi" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: nearby only" + } + }, + "id" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: nearby only" + } + }, + "it" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: nearby only" + } + }, + "ja" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: nearby only" + } + }, + "ko" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: nearby only" + } + }, + "ms" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: nearby only" + } + }, + "ne" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: nearby only" + } + }, + "nl" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: nearby only" + } + }, + "pl" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: nearby only" + } + }, + "pt" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: nearby only" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: nearby only" + } + }, + "ru" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: nearby only" + } + }, + "sv" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: nearby only" + } + }, + "ta" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: nearby only" + } + }, + "th" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: nearby only" + } + }, + "tr" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: nearby only" + } + }, + "uk" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: nearby only" + } + }, + "ur" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: nearby only" + } + }, + "vi" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: nearby only" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: nearby only" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "compose: nearby only" + } + } + } + }, + "app_info.settings.bridge.status.no_cell" : { + "comment" : "Bridge status fragment when no cell is active", + "extractionState" : "manual", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "no rendezvous cell" + } + }, + "bn" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "no rendezvous cell" + } + }, + "de" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "no rendezvous cell" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "no rendezvous cell" + } + }, + "es" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "no rendezvous cell" + } + }, + "fa" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "no rendezvous cell" + } + }, + "fil" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "no rendezvous cell" + } + }, + "fr" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "no rendezvous cell" + } + }, + "he" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "no rendezvous cell" + } + }, + "hi" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "no rendezvous cell" + } + }, + "id" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "no rendezvous cell" + } + }, + "it" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "no rendezvous cell" + } + }, + "ja" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "no rendezvous cell" + } + }, + "ko" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "no rendezvous cell" + } + }, + "ms" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "no rendezvous cell" + } + }, + "ne" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "no rendezvous cell" + } + }, + "nl" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "no rendezvous cell" + } + }, + "pl" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "no rendezvous cell" + } + }, + "pt" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "no rendezvous cell" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "no rendezvous cell" + } + }, + "ru" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "no rendezvous cell" + } + }, + "sv" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "no rendezvous cell" + } + }, + "ta" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "no rendezvous cell" + } + }, + "th" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "no rendezvous cell" + } + }, + "tr" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "no rendezvous cell" + } + }, + "uk" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "no rendezvous cell" + } + }, + "ur" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "no rendezvous cell" + } + }, + "vi" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "no rendezvous cell" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "no rendezvous cell" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "no rendezvous cell" + } + } + } + }, + "app_info.settings.bridge.status.off" : { + "comment" : "Bridge status line when the mesh bridge toggle is off", + "extractionState" : "manual", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "bridge off — only radio-range mesh traffic" + } + }, + "bn" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "bridge off — only radio-range mesh traffic" + } + }, + "de" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "bridge off — only radio-range mesh traffic" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "bridge off — only radio-range mesh traffic" + } + }, + "es" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "bridge off — only radio-range mesh traffic" + } + }, + "fa" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "bridge off — only radio-range mesh traffic" + } + }, + "fil" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "bridge off — only radio-range mesh traffic" + } + }, + "fr" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "bridge off — only radio-range mesh traffic" + } + }, + "he" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "bridge off — only radio-range mesh traffic" + } + }, + "hi" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "bridge off — only radio-range mesh traffic" + } + }, + "id" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "bridge off — only radio-range mesh traffic" + } + }, + "it" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "bridge off — only radio-range mesh traffic" + } + }, + "ja" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "bridge off — only radio-range mesh traffic" + } + }, + "ko" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "bridge off — only radio-range mesh traffic" + } + }, + "ms" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "bridge off — only radio-range mesh traffic" + } + }, + "ne" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "bridge off — only radio-range mesh traffic" + } + }, + "nl" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "bridge off — only radio-range mesh traffic" + } + }, + "pl" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "bridge off — only radio-range mesh traffic" + } + }, + "pt" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "bridge off — only radio-range mesh traffic" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "bridge off — only radio-range mesh traffic" + } + }, + "ru" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "bridge off — only radio-range mesh traffic" + } + }, + "sv" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "bridge off — only radio-range mesh traffic" + } + }, + "ta" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "bridge off — only radio-range mesh traffic" + } + }, + "th" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "bridge off — only radio-range mesh traffic" + } + }, + "tr" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "bridge off — only radio-range mesh traffic" + } + }, + "uk" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "bridge off — only radio-range mesh traffic" + } + }, + "ur" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "bridge off — only radio-range mesh traffic" + } + }, + "vi" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "bridge off — only radio-range mesh traffic" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "bridge off — only radio-range mesh traffic" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "bridge off — only radio-range mesh traffic" + } + } + } + }, + "app_info.settings.bridge.status.people" : { + "comment" : "Bridge status fragment counting bridged participants; %lld is count", + "extractionState" : "manual", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "%lld people via bridge" + } + }, + "bn" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "%lld people via bridge" + } + }, + "de" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "%lld people via bridge" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld people via bridge" + } + }, + "es" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "%lld people via bridge" + } + }, + "fa" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "%lld people via bridge" + } + }, + "fil" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "%lld people via bridge" + } + }, + "fr" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "%lld people via bridge" + } + }, + "he" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "%lld people via bridge" + } + }, + "hi" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "%lld people via bridge" + } + }, + "id" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "%lld people via bridge" + } + }, + "it" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "%lld people via bridge" + } + }, + "ja" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "%lld people via bridge" + } + }, + "ko" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "%lld people via bridge" + } + }, + "ms" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "%lld people via bridge" + } + }, + "ne" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "%lld people via bridge" + } + }, + "nl" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "%lld people via bridge" + } + }, + "pl" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "%lld people via bridge" + } + }, + "pt" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "%lld people via bridge" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "%lld people via bridge" + } + }, + "ru" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "%lld people via bridge" + } + }, + "sv" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "%lld people via bridge" + } + }, + "ta" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "%lld people via bridge" + } + }, + "th" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "%lld people via bridge" + } + }, + "tr" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "%lld people via bridge" + } + }, + "uk" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "%lld people via bridge" + } + }, + "ur" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "%lld people via bridge" + } + }, + "vi" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "%lld people via bridge" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "%lld people via bridge" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "%lld people via bridge" + } + } + } + }, "app_info.settings.bridge.subtitle" : { "extractionState" : "manual", "localizations" : { From 108818d6eb728590273785e353fff7c792bd663f Mon Sep 17 00:00:00 2001 From: Taksh Date: Sun, 9 Aug 2026 13:16:49 +0000 Subject: [PATCH 3/3] test: cover bridge status summary off state, enabled state with a cell and nearby-only compose, and the zero-bridged-peers case. --- .../Services/BridgeStatusSummaryTests.swift | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 bitchatTests/Services/BridgeStatusSummaryTests.swift diff --git a/bitchatTests/Services/BridgeStatusSummaryTests.swift b/bitchatTests/Services/BridgeStatusSummaryTests.swift new file mode 100644 index 00000000..bf9b92d2 --- /dev/null +++ b/bitchatTests/Services/BridgeStatusSummaryTests.swift @@ -0,0 +1,28 @@ +// +// BridgeStatusSummaryTests.swift +// bitchatTests +// +// This is free and unencumbered software released into the public domain. +// For more information, see +// + +import Testing +@testable import bitchat + +struct BridgeStatusSummaryTests { + @Test func offStateDoesNotMentionBridgePeople() { + let text = BridgeStatusSummary.formatted(enabled: false, cell: "u4pruy", bridgedCount: 3, nearbyOnly: false) + #expect(text.lowercased().contains("bridge off")) + } + + @Test func enabledStateIncludesCellAndCount() { + let text = BridgeStatusSummary.formatted(enabled: true, cell: "u4pruy", bridgedCount: 2, nearbyOnly: true) + #expect(text.contains("u4pruy")) + #expect(text.contains("nearby")) + } + + @Test func enabledWithZeroPeersMentionsBridgeCell() { + let text = BridgeStatusSummary.formatted(enabled: true, cell: "u4pruy", bridgedCount: 0, nearbyOnly: false) + #expect(text.localizedCaseInsensitiveContains("u4pruy") || text.localizedCaseInsensitiveContains("bridge")) + } +}