commit 9e9077bab518d73a3cdf9df6c32bb6aca834fa55
parent 7242c0bca32fad0282820854203d8446945a6333
Author: Terry Yiu <963907+tyiu@users.noreply.github.com>
Date: Sat, 31 Dec 2022 16:27:17 -0500
Internationalize all bundled user-facing strings
Enables localization to non-English locales in the future
Diffstat:
10 files changed, 93 insertions(+), 42 deletions(-)
diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj
@@ -11,6 +11,7 @@
3169CAE6294E69C000EE4006 /* EmptyTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3169CAE5294E69C000EE4006 /* EmptyTimelineView.swift */; };
3169CAED294FCCFC00EE4006 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3169CAEC294FCCFC00EE4006 /* Constants.swift */; };
31D2E847295218AF006D67F8 /* Shimmer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31D2E846295218AF006D67F8 /* Shimmer.swift */; };
+ 3A4325A82961E11400BFCD9D /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 3A4325AA2961E11400BFCD9D /* Localizable.stringsdict */; };
3ACBCB78295FE5C70037388A /* TimeAgoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ACBCB77295FE5C70037388A /* TimeAgoTests.swift */; };
4C06670128FC7C5900038D2A /* RelayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C06670028FC7C5900038D2A /* RelayView.swift */; };
4C06670428FC7EC500038D2A /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 4C06670328FC7EC500038D2A /* Kingfisher */; };
@@ -164,6 +165,7 @@
3169CAE5294E69C000EE4006 /* EmptyTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyTimelineView.swift; sourceTree = "<group>"; };
3169CAEC294FCCFC00EE4006 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Constants.swift; path = damus/Util/Constants.swift; sourceTree = SOURCE_ROOT; };
31D2E846295218AF006D67F8 /* Shimmer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Shimmer.swift; sourceTree = "<group>"; };
+ 3A4325A92961E11400BFCD9D /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
3ACBCB77295FE5C70037388A /* TimeAgoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeAgoTests.swift; sourceTree = "<group>"; };
4C06670028FC7C5900038D2A /* RelayView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayView.swift; sourceTree = "<group>"; };
4C06670528FCB08600038D2A /* ImageCarousel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCarousel.swift; sourceTree = "<group>"; };
@@ -593,6 +595,7 @@
4CE6DEE827F7A08100C66700 /* ContentView.swift */,
4CE6DEEA27F7A08200C66700 /* Assets.xcassets */,
4CE6DEEC27F7A08200C66700 /* Preview Content */,
+ 3A4325AA2961E11400BFCD9D /* Localizable.stringsdict */,
);
path = damus;
sourceTree = "<group>";
@@ -755,6 +758,7 @@
files = (
4CE6DEEE27F7A08200C66700 /* Preview Assets.xcassets in Resources */,
4CE6DEEB27F7A08200C66700 /* Assets.xcassets in Resources */,
+ 3A4325A82961E11400BFCD9D /* Localizable.stringsdict in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -938,6 +942,17 @@
};
/* End PBXTargetDependency section */
+/* Begin PBXVariantGroup section */
+ 3A4325AA2961E11400BFCD9D /* Localizable.stringsdict */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 3A4325A92961E11400BFCD9D /* en */,
+ );
+ name = Localizable.stringsdict;
+ sourceTree = "<group>";
+ };
+/* End PBXVariantGroup section */
+
/* Begin XCBuildConfiguration section */
4CE6DF0527F7A08200C66700 /* Debug */ = {
isa = XCBuildConfiguration;
diff --git a/damus/Models/Wallet.swift b/damus/Models/Wallet.swift
@@ -37,39 +37,39 @@ enum Wallet: String, CaseIterable, Identifiable {
var model: Model {
switch self {
case .system_default_wallet:
- return .init(index: -1, tag: "systemdefaultwallet", displayName: "Local default",
+ return .init(index: -1, tag: "systemdefaultwallet", displayName: NSLocalizedString("Local default", comment: "Dropdown option label for system default for Lightning wallet."),
link: "lightning:", appStoreLink: "lightning:", image: "")
case .strike:
- return .init(index: 0, tag: "strike", displayName: "Strike", link: "strike:",
+ return .init(index: 0, tag: "strike", displayName: NSLocalizedString("Strike", comment: "Dropdown option label for Lightning wallet, Strike."), link: "strike:",
appStoreLink: "https://apps.apple.com/us/app/strike-bitcoin-payments/id1488724463", image: "strike")
case .cashapp:
- return .init(index: 1, tag: "cashapp", displayName: "Cash App", link: "squarecash://",
+ return .init(index: 1, tag: "cashapp", displayName: NSLocalizedString("Cash App", comment: "Dropdown option label for Lightning wallet, Cash App."), link: "squarecash://",
appStoreLink: "https://apps.apple.com/us/app/cash-app/id711923939", image: "cashapp")
case .muun:
- return .init(index: 2, tag: "muun", displayName: "Muun", link: "muun:", appStoreLink: "https://apps.apple.com/us/app/muun-wallet/id1482037683", image: "muun")
+ return .init(index: 2, tag: "muun", displayName: NSLocalizedString("Muun", comment: "Dropdown option label for Lightning wallet, Muun."), link: "muun:", appStoreLink: "https://apps.apple.com/us/app/muun-wallet/id1482037683", image: "muun")
case .bluewallet:
- return .init(index: 3, tag: "bluewallet", displayName: "Blue Wallet", link: "bluewallet:lightning:",
+ return .init(index: 3, tag: "bluewallet", displayName: NSLocalizedString("Blue Wallet", comment: "Dropdown option label for Lightning wallet, Blue Wallet."), link: "bluewallet:lightning:",
appStoreLink: "https://apps.apple.com/us/app/bluewallet-bitcoin-wallet/id1376878040", image: "bluewallet")
case .walletofsatoshi:
- return .init(index: 4, tag: "walletofsatoshi", displayName: "Wallet Of Satoshi", link: "walletofsatoshi:lightning:",
+ return .init(index: 4, tag: "walletofsatoshi", displayName: NSLocalizedString("Wallet Of Satoshi", comment: "Dropdown option label for Lightning wallet, Wallet Of Satoshi."), link: "walletofsatoshi:lightning:",
appStoreLink: "https://apps.apple.com/us/app/wallet-of-satoshi/id1438599608", image: "walletofsatoshi")
case .zebedee:
- return .init(index: 5, tag: "zebedee", displayName: "Zebedee", link: "zebedee:lightning:",
+ return .init(index: 5, tag: "zebedee", displayName: NSLocalizedString("Zebedee", comment: "Dropdown option label for Lightning wallet, Zebedee."), link: "zebedee:lightning:",
appStoreLink: "https://apps.apple.com/us/app/zebedee-wallet/id1484394401", image: "zebedee")
case .zeusln:
- return .init(index: 6, tag: "zeusln", displayName: "Zeus LN", link: "zeusln:lightning:",
+ return .init(index: 6, tag: "zeusln", displayName: NSLocalizedString("Zeus LN", comment: "Dropdown option label for Lightning wallet, Zeus LN."), link: "zeusln:lightning:",
appStoreLink: "https://apps.apple.com/us/app/zeus-ln/id1456038895", image: "zeusln")
case .lnlink:
- return .init(index: 7, tag: "lnlink", displayName: "LNLink", link: "lnlink:lightning:",
+ return .init(index: 7, tag: "lnlink", displayName: NSLocalizedString("LNLink", comment: "Dropdown option label for Lightning wallet, LNLink."), link: "lnlink:lightning:",
appStoreLink: "https://testflight.apple.com/join/aNY4yuuZ", image: "lnlink")
case .phoenix:
- return .init(index: 8, tag: "phoenix", displayName: "Phoenix", link: "phoenix://",
+ return .init(index: 8, tag: "phoenix", displayName: NSLocalizedString("Phoenix", comment: "Dropdown option label for Lightning wallet, Phoenix."), link: "phoenix://",
appStoreLink: "https://apps.apple.com/us/app/phoenix-wallet/id1544097028", image: "phoenix")
case .breez:
- return .init(index: 9, tag: "breez", displayName: "Breez", link: "breez:",
+ return .init(index: 9, tag: "breez", displayName: NSLocalizedString("Breez", comment: "Dropdown option label for Lightning wallet, Breez."), link: "breez:",
appStoreLink: "https://apps.apple.com/us/app/breez-lightning-client-pos/id1463604142", image: "breez")
case .bitcoinbeach:
- return .init(index: 10, tag: "bitcoinbeach", displayName: "Bitcoin Beach", link: "bitcoinbeach://",
+ return .init(index: 10, tag: "bitcoinbeach", displayName: NSLocalizedString("Bitcoin Beach", comment: "Dropdown option label for Lightning wallet, Bitcoin Beach."), link: "bitcoinbeach://",
appStoreLink: "https://apps.apple.com/sv/app/bitcoin-beach-wallet/id1531383905", image: "bbw")
}
}
diff --git a/damus/Views/CreateAccountView.swift b/damus/Views/CreateAccountView.swift
@@ -40,26 +40,26 @@ struct CreateAccountView: View {
}
VStack {
SignupForm {
- FormLabel("Username")
+ FormLabel(NSLocalizedString("Username", comment: "Label to prompt username entry."))
HStack(spacing: 0.0) {
Text("@")
.foregroundColor(.white)
.padding(.leading, -25.0)
- FormTextInput("satoshi", text: $account.nick_name)
+ FormTextInput(NSLocalizedString("satoshi", comment: "Example username of Bitcoin creator(s), Satoshi Nakamoto."), text: $account.nick_name)
.autocorrectionDisabled(true)
.textInputAutocapitalization(.never)
}
- FormLabel("Display Name", optional: true)
- FormTextInput("Satoshi Nakamoto", text: $account.real_name)
+ FormLabel(NSLocalizedString("Display Name", comment: "Label to prompt display name entry."), optional: true)
+ FormTextInput(NSLocalizedString("Satoshi Nakamoto", comment: "Name of Bitcoin creator(s)."), text: $account.real_name)
.textInputAutocapitalization(.words)
- FormLabel("About", optional: true)
- FormTextInput("Creator(s) of Bitcoin. Absolute legend.", text: $account.about)
+ FormLabel(NSLocalizedString("About", comment: "Label to prompt for about text entry for user to describe about themself."), optional: true)
+ FormTextInput(NSLocalizedString("Creator(s) of Bitcoin. Absolute legend.", comment: "Example description about Bitcoin creator(s), Satoshi Nakamoto."), text: $account.about)
- FormLabel("Account ID")
+ FormLabel(NSLocalizedString("Account ID", comment: "Label to indicate the public ID of the account."))
.onTapGesture {
regen_key()
}
@@ -75,7 +75,7 @@ struct CreateAccountView: View {
NavigationLink(destination: SaveKeysView(account: account), isActive: $is_done) {
EmptyView()
}
- DamusWhiteButton("Create") {
+ DamusWhiteButton(NSLocalizedString("Create", comment: "Button to create account.")) {
self.is_done = true
}
.padding()
diff --git a/damus/Views/EditMetadataView.swift b/damus/Views/EditMetadataView.swift
@@ -142,7 +142,7 @@ struct EditMetadataView: View {
}
Section("About Me") {
- let placeholder = "Absolute Boss"
+ let placeholder = NSLocalizedString("Absolute Boss", comment: "Placeholder text for About Me description.")
ZStack(alignment: .topLeading) {
TextEditor(text: $about)
.textInputAutocapitalization(.sentences)
@@ -169,9 +169,9 @@ struct EditMetadataView: View {
Text("NIP-05 Verification")
}, footer: {
if let parts = nip05_parts {
- Text("'\(parts.username)' at '\(parts.host)' will be used for verification")
+ Text(String.localizedStringWithFormat("'%@' at '%@' will be used for verification", parts.username, parts.host))
} else {
- Text("'\(nip05)' is an invalid nip05 identifier. It should look like an email.")
+ Text(String.localizedStringWithFormat("'%@' is an invalid nip05 identifier. It should look like an email.", nip05))
}
})
diff --git a/damus/Views/EventView.swift b/damus/Views/EventView.swift
@@ -401,7 +401,7 @@ func reply_desc(profiles: Profiles, event: NostrEvent) -> String {
let n = desc.others
if desc.pubkeys.count == 0 {
- return "Reply to self"
+ return NSLocalizedString("Reply to self", comment: "Label to indicate that the user is replying to themself.")
}
let names: [String] = pubkeys.map {
@@ -411,20 +411,14 @@ func reply_desc(profiles: Profiles, event: NostrEvent) -> String {
if names.count == 2 {
if n > 2 {
- let and_other = reply_others_desc(n: n, n_pubkeys: pubkeys.count)
- return "Replying to \(names[0]), \(names[1])\(and_other)"
+ let othersCount = n - pubkeys.count
+ return String(format: NSLocalizedString("replying_to_two_and_others", comment: "Label to indicate that the user is replying to 2 users and others."), othersCount, names[0], names[1])
}
- return "Replying to \(names[0]) & \(names[1])"
+ return String.localizedStringWithFormat("Replying to %@ & %@", names[0], names[1])
}
- let and_other = reply_others_desc(n: n, n_pubkeys: pubkeys.count)
- return "Replying to \(names[0])\(and_other)"
-}
-
-func reply_others_desc(n: Int, n_pubkeys: Int) -> String {
- let other = n - n_pubkeys
- let plural = other == 1 ? "" : "s"
- return n > 1 ? " & \(other) other\(plural)" : ""
+ let othersCount = n - pubkeys.count
+ return String(format: NSLocalizedString("replying_to_one_and_others", comment: "Label to indicate that the user is replying to 1 user and others."), othersCount, names[0])
}
diff --git a/damus/Views/PostView.swift b/damus/Views/PostView.swift
@@ -12,7 +12,7 @@ enum NostrPostResult {
case cancel
}
-let POST_PLACEHOLDER = "Type your post here..."
+let POST_PLACEHOLDER = NSLocalizedString("Type your post here...", comment: "Text box prompt to ask user to type their post.")
struct PostView: View {
@State var post: String = ""
diff --git a/damus/Views/ProfileView.swift b/damus/Views/ProfileView.swift
@@ -22,13 +22,13 @@ enum FollowState {
func follow_btn_txt(_ fs: FollowState) -> String {
switch fs {
case .follows:
- return "Unfollow"
+ return NSLocalizedString("Unfollow", comment: "Button to unfollow a user.")
case .following:
- return "Following..."
+ return NSLocalizedString("Following...", comment: "Label to indicate that the user is in the process of following another user.")
case .unfollowing:
- return "Unfollowing..."
+ return NSLocalizedString("Unfollowing...", comment: "Label to indicate that the user is in the process of unfollowing another user.")
case .unfollows:
- return "Follow"
+ return NSLocalizedString("Follow", comment: "Button to follow a user.")
}
}
diff --git a/damus/Views/SaveKeysView.swift b/damus/Views/SaveKeysView.swift
@@ -67,7 +67,7 @@ struct SaveKeysView: View {
complete_account_creation(account)
}
} else {
- DamusWhiteButton("Let's go!") {
+ DamusWhiteButton(NSLocalizedString("Let's go!", comment: "Button to complete account creation and start using the app.")) {
complete_account_creation(account)
}
}
diff --git a/damus/Views/SetupView.swift b/damus/Views/SetupView.swift
@@ -60,7 +60,7 @@ struct SetupView: View {
CarouselView()
- DamusWhiteButton("Create Account") {
+ DamusWhiteButton(NSLocalizedString("Create Account", comment: "Button to create an account.")) {
self.state = .create_account
}
diff --git a/damus/en.lproj/Localizable.stringsdict b/damus/en.lproj/Localizable.stringsdict
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>replying_to_one_and_others</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>Replying to %2$@%#@others@</string>
+ <key>others</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>zero</key>
+ <string></string>
+ <key>one</key>
+ <string> & 1 other</string>
+ <key>other</key>
+ <string> & %d others</string>
+ </dict>
+ </dict>
+ <key>replying_to_two_and_others</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>Replying to %2$@, %3$@%#@others@</string>
+ <key>others</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>zero</key>
+ <string></string>
+ <key>one</key>
+ <string> & 1 other</string>
+ <key>other</key>
+ <string> & %d others</string>
+ </dict>
+ </dict>
+</dict>
+</plist>