From 6a553dbbd6a5d165dba635414ff19c5b80890118 Mon Sep 17 00:00:00 2001 From: Fethi El Hassasna Date: Wed, 11 Feb 2026 22:08:52 -0500 Subject: [PATCH 1/2] Localize hardcoded About screen labels via String Catalog --- SwiftRadio/Config/Config.swift | 14 +-- SwiftRadio/Config/Content.swift | 13 +++ SwiftRadio/Localizable.xcstrings | 99 +++++++++++++++++++ .../ViewControllers/AboutViewController.swift | 2 +- 4 files changed, 120 insertions(+), 8 deletions(-) diff --git a/SwiftRadio/Config/Config.swift b/SwiftRadio/Config/Config.swift index f3a68e56..83a24099 100755 --- a/SwiftRadio/Config/Config.swift +++ b/SwiftRadio/Config/Config.swift @@ -61,25 +61,25 @@ struct Config { struct About { static let sections: [InfoSection] = [ InfoSection(title: Content.About.Sections.features, items: [ - .features() + .features(title: Content.About.Items.features) ]), InfoSection(title: Content.About.Sections.contact, items: [ - .email(address: Config.email), + .email(title: Content.About.Items.email, address: Config.email), .link(title: Content.About.feedback.0, subtitle: Content.About.feedback.1, url: Config.feedbackURL) ]), InfoSection(title: Content.About.Sections.support, items: [ - .rateApp(appID: "YOUR_APP_ID"), - .share(text: Content.About.shareText) + .rateApp(title: Content.About.Items.rateApp, appID: "YOUR_APP_ID"), + .share(title: Content.About.Items.shareApp, text: Content.About.shareText) ]), InfoSection(title: Content.About.Sections.credits, items: [ - .libraries(), - .credits(owner: "analogcode", repo: "Swift-Radio-Pro") + .libraries(title: Content.About.Items.libraries), + .credits(title: Content.About.Items.contributors, subtitle: Content.About.Items.specialThanks, owner: "analogcode", repo: "Swift-Radio-Pro") ]), InfoSection(title: Content.About.Sections.legal, items: [ .link(title: Content.About.license.0, subtitle: Content.About.license.1, url: Config.licenseURL) ]), InfoSection(title: Content.About.Sections.version, items: [ - .version() + .version(title: Content.About.Items.appVersion) ]) ] } diff --git a/SwiftRadio/Config/Content.swift b/SwiftRadio/Config/Content.swift index e318ea3c..4db5dfda 100644 --- a/SwiftRadio/Config/Content.swift +++ b/SwiftRadio/Config/Content.swift @@ -27,9 +27,22 @@ struct Content { static let version = String(localized: "about.sections.version") } + static let copyright = String(localized: "about.copyright") + static let feedback = (String(localized: "about.feedback.title"), String(localized: "about.feedback.message")) static let shareText = String(localized: "about.shareText") static let license = (String(localized: "about.license.title"), String(localized: "about.license.detail")) + + struct Items { + static let features = String(localized: "about.items.features") + static let email = String(localized: "about.items.email") + static let rateApp = String(localized: "about.items.rateApp") + static let shareApp = String(localized: "about.items.shareApp") + static let libraries = String(localized: "about.items.libraries") + static let contributors = String(localized: "about.items.contributors") + static let specialThanks = String(localized: "about.items.specialThanks") + static let appVersion = String(localized: "about.items.appVersion") + } } struct Contributors { diff --git a/SwiftRadio/Localizable.xcstrings b/SwiftRadio/Localizable.xcstrings index 14936131..bce80ea6 100644 --- a/SwiftRadio/Localizable.xcstrings +++ b/SwiftRadio/Localizable.xcstrings @@ -23,6 +23,17 @@ } } }, + "about.copyright" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Copyright" + } + } + } + }, "about.footerAuthors" : { "extractionState" : "manual", "localizations" : { @@ -45,6 +56,94 @@ } } }, + "about.items.appVersion" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "App Version" + } + } + } + }, + "about.items.contributors" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contributors" + } + } + } + }, + "about.items.email" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Email" + } + } + } + }, + "about.items.features" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Features" + } + } + } + }, + "about.items.libraries" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Open Source Libraries" + } + } + } + }, + "about.items.rateApp" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rate the App" + } + } + } + }, + "about.items.shareApp" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Share the App" + } + } + } + }, + "about.items.specialThanks" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Special Thanks" + } + } + } + }, "about.headerText" : { "extractionState" : "manual", "localizations" : { diff --git a/SwiftRadio/ViewControllers/AboutViewController.swift b/SwiftRadio/ViewControllers/AboutViewController.swift index 30ca8c28..68cfdd1f 100755 --- a/SwiftRadio/ViewControllers/AboutViewController.swift +++ b/SwiftRadio/ViewControllers/AboutViewController.swift @@ -186,7 +186,7 @@ class AboutViewController: UITableViewController { footerLabel.text = """ \(Content.About.footerAuthors) - Copyright © \(Calendar.current.component(.year, from: Date())) \(Content.About.footerCopyright) + \(Content.About.copyright) © \(Calendar.current.component(.year, from: Date())) \(Content.About.footerCopyright) """ stackView.addArrangedSubview(logoImageView) From aa866d83c12ed6c609bae7481300b4b89c4b4f0f Mon Sep 17 00:00:00 2001 From: Fethi El Hassasna Date: Fri, 13 Feb 2026 21:10:29 -0500 Subject: [PATCH 2/2] Update README.md --- README.md | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 60eeeb7c..2a123086 100755 --- a/README.md +++ b/README.md @@ -49,35 +49,37 @@ Images can be local (asset name without `http`) or remote (full URL). ### Customizing Text and Translation -All user-facing strings are managed through `Localizable.xcstrings` (the String Catalog). Open it in Xcode to change the default English text or add new languages — no code changes required. +All user-facing strings are managed through `Localizable.xcstrings` (the String Catalog). Open it in Xcode to change the default English text or add new languages. No code changes required. ## Dependencies -- [FRadioPlayer](https://github.com/fethica/FRadioPlayer) — streaming and metadata -- [LNPopupController](https://github.com/LeoNatan/LNPopupController) — now playing popup bar -- [NVActivityIndicatorView](https://github.com/ninjaprox/NVActivityIndicatorView) — loading indicators -- [MarqueeLabel](https://github.com/cbpowell/MarqueeLabel) — scrolling text labels +- [FRadioPlayer](https://github.com/fethica/FRadioPlayer) --streaming and metadata +- [LNPopupController](https://github.com/LeoNatan/LNPopupController) --now playing popup bar +- [NVActivityIndicatorView](https://github.com/ninjaprox/NVActivityIndicatorView) --loading indicators +- [MarqueeLabel](https://github.com/cbpowell/MarqueeLabel) --scrolling text labels All managed via Swift Package Manager. ## Contributing -Contributions are welcome. Please branch off [`dev`](https://github.com/analogcode/Swift-Radio-Pro/tree/dev) and open a pull request — do not commit directly to `master`. +Contributions are welcome. Please branch off [`dev`](https://github.com/analogcode/Swift-Radio-Pro/tree/dev) and open a pull request --do not commit directly to `master`. ## Single Station Version -Looking for a simpler, single-station version of this app? We offer a ready-to-go codebase for **$50** — no extra fees. +Looking for a simpler, single-station version? It skips the station list and launches straight into the player. -PayPal [fethica@me.com](mailto:fethica@me.com) or use [PayPal.Me](https://www.paypal.me/fethicaEH), and we will send the code within 24 hours with setup instructions. All funds support the project. +[![Buy on Payhip](https://img.shields.io/badge/Buy-Single%20Station-blue)](https://payhip.com/b/x15QB) + +All proceeds go directly toward maintaining and improving Swift Radio. For custom work or more advanced needs, reach out to [Fethi](mailto:contact@fethica.com). -**Built something with Swift Radio?** We'd love to see it — drop us a line at [contact@fethica.com](mailto:contact@fethica.com). +**Built something with Swift Radio?** We'd love to see it --drop us a line at [contact@fethica.com](mailto:contact@fethica.com). ## Credits -- [Fethi](https://fethica.com) — co-organizer and lead developer -- [Matthew Fecher](http://matthewfecher.com) — creator, [AudioKit Pro](https://audiokitpro.com) +- [Fethi](https://fethica.com) --co-organizer and lead developer +- [Matthew Fecher](http://matthewfecher.com) --creator, [AudioKit Pro](https://audiokitpro.com) - [All contributors](https://github.com/analogcode/Swift-Radio-Pro/graphs/contributors) ## License