Fix Localizations (#684)

* Update all `NSLocalizedString` with `L10n.string`

+ combine with `L10n.format`

* Handle Localizations + Swift Package
This commit is contained in:
Islam
2025-09-26 11:09:10 +02:00
committed by GitHub
parent 9abfab3248
commit d01538a2ea
10 changed files with 52 additions and 44 deletions
+1
View File
@@ -72,6 +72,7 @@
isa = PBXFileSystemSynchronizedBuildFileExceptionSet; isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = ( membershipExceptions = (
Services/TransportConfig.swift, Services/TransportConfig.swift,
Utils/Localization.swift,
); );
target = 57CA17A36A2532A6CFF367BB /* bitchatShareExtension */; target = 57CA17A36A2532A6CFF367BB /* bitchatShareExtension */;
}; };
+4 -4
View File
@@ -77,17 +77,17 @@ final class LocationNotesManager: ObservableObject {
private let dependencies: LocationNotesDependencies private let dependencies: LocationNotesDependencies
private enum Strings { private enum Strings {
static let noRelays = NSLocalizedString( static let noRelays = L10n.string(
"location_notes.error.no_relays", "location_notes.error.no_relays",
comment: "Shown when no geo relays are available near the selected location" comment: "Shown when no geo relays are available near the selected location"
) )
static func failedToSend(_ detail: String) -> String { static func failedToSend(_ detail: String) -> String {
let format = NSLocalizedString( L10n.string(
"location_notes.error.failed_to_send", "location_notes.error.failed_to_send",
comment: "Shown when a location note fails to send" comment: "Shown when a location note fails to send",
detail
) )
return String(format: format, detail)
} }
} }
+14 -5
View File
@@ -1,12 +1,21 @@
import Foundation import Foundation
enum L10n { enum L10n {
static func string(_ key: String, comment: String) -> String { static func string(_ key: String, comment: String, _ args: CVarArg...) -> String {
NSLocalizedString(key, comment: comment) let basic = NSLocalizedString(key, bundle: .localization, comment: comment)
if args.isEmpty {
return basic
}
return String(format: basic, locale: .current, arguments: args)
} }
}
static func format(_ key: String, comment: String, _ args: CVarArg...) -> String { private extension Bundle {
let format = NSLocalizedString(key, comment: comment) static var localization: Bundle {
return String(format: format, locale: Locale.current, arguments: args) #if SWIFT_PACKAGE
return Bundle.module
#else
return Bundle.main
#endif
} }
} }
+6 -6
View File
@@ -2077,7 +2077,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
for (k, v) in nostrKeyMapping where v.lowercased() == hex { nostrKeyMapping.removeValue(forKey: k) } for (k, v) in nostrKeyMapping where v.lowercased() == hex { nostrKeyMapping.removeValue(forKey: k) }
addSystemMessage( addSystemMessage(
L10n.format( L10n.string(
"system.geohash.blocked", "system.geohash.blocked",
comment: "System message shown when a user is blocked in geohash chats", comment: "System message shown when a user is blocked in geohash chats",
displayName displayName
@@ -2088,7 +2088,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
func unblockGeohashUser(pubkeyHexLowercased: String, displayName: String) { func unblockGeohashUser(pubkeyHexLowercased: String, displayName: String) {
identityManager.setNostrBlocked(pubkeyHexLowercased, isBlocked: false) identityManager.setNostrBlocked(pubkeyHexLowercased, isBlocked: false)
addSystemMessage( addSystemMessage(
L10n.format( L10n.string(
"system.geohash.unblocked", "system.geohash.unblocked",
comment: "System message shown when a user is unblocked in geohash chats", comment: "System message shown when a user is unblocked in geohash chats",
displayName displayName
@@ -2278,7 +2278,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
if unifiedPeerService.isBlocked(peerID) { if unifiedPeerService.isBlocked(peerID) {
let nickname = meshService.peerNickname(peerID: peerID) ?? "user" let nickname = meshService.peerNickname(peerID: peerID) ?? "user"
addSystemMessage( addSystemMessage(
L10n.format( L10n.string(
"system.dm.blocked_recipient", "system.dm.blocked_recipient",
comment: "System message when attempting to message a blocked user", comment: "System message when attempting to message a blocked user",
nickname nickname
@@ -2353,7 +2353,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
) )
} }
addSystemMessage( addSystemMessage(
L10n.format( L10n.string(
"system.dm.unreachable", "system.dm.unreachable",
comment: "System message when a recipient is unreachable", comment: "System message when a recipient is unreachable",
recipientNickname ?? L10n.string("system.common.user", comment: "Fallback recipient name") recipientNickname ?? L10n.string("system.common.user", comment: "Fallback recipient name")
@@ -2561,7 +2561,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
// Check if the peer is blocked // Check if the peer is blocked
if unifiedPeerService.isBlocked(peerID) { if unifiedPeerService.isBlocked(peerID) {
addSystemMessage( addSystemMessage(
L10n.format( L10n.string(
"system.chat.blocked", "system.chat.blocked",
comment: "System message when starting chat fails because peer is blocked", comment: "System message when starting chat fails because peer is blocked",
peerNickname peerNickname
@@ -2574,7 +2574,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
if let peer = unifiedPeerService.getPeer(by: peerID), if let peer = unifiedPeerService.getPeer(by: peerID),
peer.isFavorite && !peer.theyFavoritedUs && !peer.isConnected { peer.isFavorite && !peer.theyFavoritedUs && !peer.isConnected {
addSystemMessage( addSystemMessage(
L10n.format( L10n.string(
"system.chat.requires_favorite", "system.chat.requires_favorite",
comment: "System message when mutual favorite requirement blocks chat", comment: "System message when mutual favorite requirement blocks chat",
peerNickname peerNickname
+11 -13
View File
@@ -1225,7 +1225,7 @@ struct ContentView: View {
} }
.buttonStyle(.plain) .buttonStyle(.plain)
.accessibilityLabel( .accessibilityLabel(
L10n.format( L10n.string(
"content.accessibility.toggle_bookmark", "content.accessibility.toggle_bookmark",
comment: "Accessibility label for toggling a geohash bookmark", comment: "Accessibility label for toggling a geohash bookmark",
ch.geohash ch.geohash
@@ -1271,13 +1271,11 @@ struct ContentView: View {
Image(systemName: "person.2.fill") Image(systemName: "person.2.fill")
.font(.system(size: headerPeerIconSize, weight: .regular)) .font(.system(size: headerPeerIconSize, weight: .regular))
.accessibilityLabel( .accessibilityLabel(
NSString.localizedStringWithFormat( L10n.string(
NSLocalizedString( "content.accessibility.people_count",
"content.accessibility.people_count", comment: "Accessibility label announcing number of people in header",
comment: "Accessibility label announcing number of people in header"
) as NSString,
headerOtherPeersCount headerOtherPeersCount
) as String )
) )
Text("\(headerOtherPeersCount)") Text("\(headerOtherPeersCount)")
.font(.system(size: headerPeerCountFontSize, weight: .regular, design: .monospaced)) .font(.system(size: headerPeerCountFontSize, weight: .regular, design: .monospaced))
@@ -1578,7 +1576,7 @@ struct ContentView: View {
encryptionStatus == .noiseSecured ? textColor : encryptionStatus == .noiseSecured ? textColor :
Color.red) Color.red)
.accessibilityLabel( .accessibilityLabel(
L10n.format( L10n.string(
"content.accessibility.encryption_status", "content.accessibility.encryption_status",
comment: "Accessibility label announcing encryption status", comment: "Accessibility label announcing encryption status",
encryptionStatus.accessibilityDescription encryptionStatus.accessibilityDescription
@@ -1588,7 +1586,7 @@ struct ContentView: View {
} }
} }
.accessibilityLabel( .accessibilityLabel(
L10n.format( L10n.string(
"content.accessibility.private_chat_header", "content.accessibility.private_chat_header",
comment: "Accessibility label describing the private chat header", comment: "Accessibility label describing the private chat header",
privatePeerNick privatePeerNick
@@ -1751,7 +1749,7 @@ struct DeliveryStatusView: View {
private enum Strings { private enum Strings {
static func delivered(to nickname: String) -> String { static func delivered(to nickname: String) -> String {
L10n.format( L10n.string(
"content.delivery.delivered_to", "content.delivery.delivered_to",
comment: "Tooltip for delivered private messages", comment: "Tooltip for delivered private messages",
nickname nickname
@@ -1759,7 +1757,7 @@ struct DeliveryStatusView: View {
} }
static func read(by nickname: String) -> String { static func read(by nickname: String) -> String {
L10n.format( L10n.string(
"content.delivery.read_by", "content.delivery.read_by",
comment: "Tooltip for read private messages", comment: "Tooltip for read private messages",
nickname nickname
@@ -1767,7 +1765,7 @@ struct DeliveryStatusView: View {
} }
static func failed(_ reason: String) -> String { static func failed(_ reason: String) -> String {
L10n.format( L10n.string(
"content.delivery.failed", "content.delivery.failed",
comment: "Tooltip for failed message delivery", comment: "Tooltip for failed message delivery",
reason reason
@@ -1775,7 +1773,7 @@ struct DeliveryStatusView: View {
} }
static func deliveredToMembers(_ reached: Int, _ total: Int) -> String { static func deliveredToMembers(_ reached: Int, _ total: Int) -> String {
L10n.format( L10n.string(
"content.delivery.delivered_members", "content.delivery.delivered_members",
comment: "Tooltip for partially delivered messages", comment: "Tooltip for partially delivered messages",
reached, reached,
+1 -1
View File
@@ -32,7 +32,7 @@ struct FingerprintView: View {
static let notVerifiedBadge: LocalizedStringKey = "fingerprint.badge.not_verified" static let notVerifiedBadge: LocalizedStringKey = "fingerprint.badge.not_verified"
static let verifiedMessage: LocalizedStringKey = "fingerprint.message.verified" static let verifiedMessage: LocalizedStringKey = "fingerprint.message.verified"
static func verifyHint(_ nickname: String) -> String { static func verifyHint(_ nickname: String) -> String {
L10n.format( L10n.string(
"fingerprint.message.verify_hint", "fingerprint.message.verify_hint",
comment: "Instruction to compare fingerprints with a named peer", comment: "Instruction to compare fingerprints with a named peer",
nickname nickname
+5 -5
View File
@@ -54,7 +54,7 @@ struct LocationChannelsSheet: View {
} }
static func subtitlePrefix(geohash: String, coverage: String) -> String { static func subtitlePrefix(geohash: String, coverage: String) -> String {
L10n.format( L10n.string(
"location_channels.subtitle_prefix", "location_channels.subtitle_prefix",
comment: "Subtitle prefix showing geohash and coverage", comment: "Subtitle prefix showing geohash and coverage",
geohash, geohash,
@@ -64,7 +64,7 @@ struct LocationChannelsSheet: View {
static func subtitle(prefix: String, name: String?) -> String { static func subtitle(prefix: String, name: String?) -> String {
guard let name, !name.isEmpty else { return prefix } guard let name, !name.isEmpty else { return prefix }
return L10n.format( return L10n.string(
"location_channels.subtitle_with_name", "location_channels.subtitle_with_name",
comment: "Subtitle combining prefix and resolved location name", comment: "Subtitle combining prefix and resolved location name",
prefix, prefix,
@@ -73,11 +73,11 @@ struct LocationChannelsSheet: View {
} }
private static func rowTitle(label: String, count: Int) -> String { private static func rowTitle(label: String, count: Int) -> String {
let format = NSLocalizedString( L10n.string(
"location_channels.row_title", "location_channels.row_title",
comment: "List row title with participant count" comment: "List row title with participant count",
label, count
) )
return NSString.localizedStringWithFormat(format as NSString, label, count) as String
} }
} }
+3 -3
View File
@@ -145,11 +145,11 @@ struct LocationNotesView: View {
} }
private func headerTitle(for count: Int) -> String { private func headerTitle(for count: Int) -> String {
let format = NSLocalizedString( L10n.string(
"location_notes.header", "location_notes.header",
comment: "Header displaying the geohash and localized note count" comment: "Header displaying the geohash and localized note count",
geohash, count
) )
return NSString.localizedStringWithFormat(format as NSString, geohash, count) as String
} }
private var notesContent: some View { private var notesContent: some View {
+1 -1
View File
@@ -120,7 +120,7 @@ struct QRScanView: View {
static let pastePrompt: LocalizedStringKey = "verification.scan.paste_prompt" static let pastePrompt: LocalizedStringKey = "verification.scan.paste_prompt"
static let validate: LocalizedStringKey = "verification.scan.validate" static let validate: LocalizedStringKey = "verification.scan.validate"
static func requested(_ nickname: String) -> String { static func requested(_ nickname: String) -> String {
L10n.format( L10n.string(
"verification.scan.status.requested", "verification.scan.status.requested",
comment: "Status text when verification is requested for a nickname", comment: "Status text when verification is requested for a nickname",
nickname nickname
@@ -16,12 +16,12 @@ final class ShareViewController: UIViewController {
private static let groupID = "group.chat.bitchat" private static let groupID = "group.chat.bitchat"
private enum Strings { private enum Strings {
static let nothingToShare = NSLocalizedString("share.status.nothing_to_share", comment: "Shown when the share extension receives no content") static let nothingToShare = L10n.string("share.status.nothing_to_share", comment: "Shown when the share extension receives no content")
static let noShareableContent = NSLocalizedString("share.status.no_shareable_content", comment: "Shown when provided content cannot be shared") static let noShareableContent = L10n.string("share.status.no_shareable_content", comment: "Shown when provided content cannot be shared")
static let sharedLinkTitleFallback = NSLocalizedString("share.fallback.shared_link_title", comment: "Fallback title when saving a shared link") static let sharedLinkTitleFallback = L10n.string("share.fallback.shared_link_title", comment: "Fallback title when saving a shared link")
static let sharedLinkConfirmation = NSLocalizedString("share.status.shared_link", comment: "Confirmation after successfully sharing a link") static let sharedLinkConfirmation = L10n.string("share.status.shared_link", comment: "Confirmation after successfully sharing a link")
static let sharedTextConfirmation = NSLocalizedString("share.status.shared_text", comment: "Confirmation after successfully sharing text") static let sharedTextConfirmation = L10n.string("share.status.shared_text", comment: "Confirmation after successfully sharing text")
static let failedToEncode = NSLocalizedString("share.status.failed_to_encode", comment: "Shown when the share payload cannot be encoded") static let failedToEncode = L10n.string("share.status.failed_to_encode", comment: "Shown when the share payload cannot be encoded")
} }
private let statusLabel: UILabel = { private let statusLabel: UILabel = {