From d4e6e6929d6449f65bd83e9445592e8bb1951f80 Mon Sep 17 00:00:00 2001 From: Andrew Montgomery Date: Wed, 4 Sep 2024 12:56:22 -0500 Subject: [PATCH 1/9] Add global `SDKLocalizedString` type --- .../Utility/SDKLocalizedString.swift | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 Sources/GravatarUI/Utility/SDKLocalizedString.swift diff --git a/Sources/GravatarUI/Utility/SDKLocalizedString.swift b/Sources/GravatarUI/Utility/SDKLocalizedString.swift new file mode 100644 index 00000000..ff352be7 --- /dev/null +++ b/Sources/GravatarUI/Utility/SDKLocalizedString.swift @@ -0,0 +1,39 @@ +import Foundation + +/// Use this to express *intent* on your API that the string you are manipulating / returning is intended to already be localized +/// and its value to have been provided via a call to `NSLocalizedString` or `SDKLocalizedString`. +/// +/// Semantically speaking, a method taking or returning a `LocalizedString` is signaling that you can display said UI string +/// to the end user, without the need to be treated as a key to be localized. The string is expected to already have been localized +/// at that point of the code, via a call to `NSLocalizedString`, `SDKLocalizedString` or similar upstream in the code. +/// +/// - Note: Remember though that, as a `typealias`, this won't provide any compile-time guarantee. +typealias LocalizedString = String + +/// Use this function instead of `NSLocalizedString` to reference localized strings **from the library module**. +/// +/// You should use this `SDKLocalizedString` method in place of `NSLocalizedString` for all localized strings in the SDK. +/// This ensures that an app target that imports this module will perform localization lookup in the module, and not in the main app bundle, +/// which is the default when using `NSLocalizedStrings()` without specifying `bundle = .module`. +/// +/// - Note: +/// Tooling: Be sure to pass this function's name as a custom routine when parsing the code to generate the main `.strings` file, +/// using `genstrings -s SDKLocalizedString`, so that this helper method is recognized. You will also have to +/// exclude this very file from being parsed by `genstrings`, so that it won't accidentally misinterpret that routine/function definition +/// below as a call site and generate an error because of it. +/// +/// - Parameters: +/// - key: An identifying value used to reference a localized string. +/// - tableName: The basename of the `.strings` file **in the app bundle** containing +/// the localized values. If `tableName` is `nil`, the `Localizable` table is used. +/// - value: The English/default copy for the string. This is the user-visible string that the +/// translators will use as original to translate, and also the string returned when the localized string for +/// `key` cannot be found in the table. If `value` is `nil` or empty, `key` would be returned instead. +/// - comment: A note to the translator describing the context where the localized string is presented to the user. +/// +/// - Returns: A localized version of the string designated by `key` in the table identified by `tableName`. +/// If the localized string for `key` cannot be found within the table, `value` is returned. +/// (However, `key` is returned instead when `value` is `nil` or the empty string). +func SDKLocalizedString(_ key: String, tableName: String? = nil, value: String? = nil, comment: String) -> LocalizedString { + Bundle.module.localizedString(forKey: key, value: value, table: tableName) +} From bd7bbaa623a835aee731cf40648bf22394680561 Mon Sep 17 00:00:00 2001 From: Andrew Montgomery Date: Wed, 4 Sep 2024 12:56:44 -0500 Subject: [PATCH 2/9] Update genstrings to support SDKLocalizedString --- fastlane/lanes/localization.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fastlane/lanes/localization.rb b/fastlane/lanes/localization.rb index 470b644f..25a97673 100644 --- a/fastlane/lanes/localization.rb +++ b/fastlane/lanes/localization.rb @@ -93,6 +93,8 @@ SOURCES_TO_LOCALIZE.each do |source| ios_generate_strings_file_from_code( paths: source.source_paths, + exclude: ['**/SDKLocalizedString.swift'], + routines: ['SDKLocalizedString'], output_dir: source.base_localization_root ) From 65009fbebbc741ae23b76d94fdcc44d2b971e372 Mon Sep 17 00:00:00 2001 From: Andrew Montgomery Date: Wed, 4 Sep 2024 12:57:05 -0500 Subject: [PATCH 3/9] Refactor NSLocalizedString --> SDKLocalizedString --- .../Model/ClaimProfileModel.swift | 9 ++--- .../ProfileFields/ProfileButtonBuilder.swift | 9 ++--- .../AvatarPickerProfileView.swift | 3 +- .../AvatarPicker/AvatarPickerView.swift | 39 +++++++------------ 4 files changed, 20 insertions(+), 40 deletions(-) diff --git a/Sources/GravatarUI/ProfileFields/Model/ClaimProfileModel.swift b/Sources/GravatarUI/ProfileFields/Model/ClaimProfileModel.swift index 6df355ab..29ba7e15 100644 --- a/Sources/GravatarUI/ProfileFields/Model/ClaimProfileModel.swift +++ b/Sources/GravatarUI/ProfileFields/Model/ClaimProfileModel.swift @@ -1,23 +1,20 @@ import UIKit struct ClaimProfileModel: ProfileModel { - let description: String = NSLocalizedString( + let description: String = SDKLocalizedString( "ClaimProfile.Label.AboutMe", - bundle: .module, value: "Tell the world who you are. Your avatar and bio that follows you across the web.", comment: "Text on a sample Gravatar profile, appearing in the place where a Gravatar profile would display your short biography." ) - let location: String = NSLocalizedString( + let location: String = SDKLocalizedString( "ClaimProfile.Label.Location", - bundle: .module, value: "Add your location, pronouns, etc", comment: "Text on a sample Gravatar profile, appearing in the place where a Gravatar profile would display information like location, your preferred pronouns, etc." ) - var displayName: String = NSLocalizedString( + var displayName: String = SDKLocalizedString( "ClaimProfile.Label.DisplayName", - bundle: .module, value: "Your Name", comment: "Text on a sample Gravatar profile, appearing in the place where your name would normally appear on your Gravatar profile after you claim it." ) diff --git a/Sources/GravatarUI/ProfileFields/ProfileButtonBuilder.swift b/Sources/GravatarUI/ProfileFields/ProfileButtonBuilder.swift index 3fcbd527..1ac34e67 100644 --- a/Sources/GravatarUI/ProfileFields/ProfileButtonBuilder.swift +++ b/Sources/GravatarUI/ProfileFields/ProfileButtonBuilder.swift @@ -17,23 +17,20 @@ extension ProfileButtonStyle { var localizedTitle: String { switch self { case .view: - NSLocalizedString( + SDKLocalizedString( "ProfileButton.title.view", - bundle: .module, value: "View profile", comment: "Title for a button that allows you to view your Gravatar profile" ) case .edit: - NSLocalizedString( + SDKLocalizedString( "ProfileButton.title.edit", - bundle: .module, value: "Edit profile", comment: "Title for a button that allows you to edit your Gravatar profile" ) case .create: - NSLocalizedString( + SDKLocalizedString( "ProfileButton.title.create", - bundle: .module, value: "Claim profile", comment: "Title for a button that allows you to claim a new Gravatar profile" ) diff --git a/Sources/GravatarUI/SwiftUI/AvatarPicker/AvatarPickerProfileView.swift b/Sources/GravatarUI/SwiftUI/AvatarPicker/AvatarPickerProfileView.swift index c509b9ca..0c93adef 100644 --- a/Sources/GravatarUI/SwiftUI/AvatarPicker/AvatarPickerProfileView.swift +++ b/Sources/GravatarUI/SwiftUI/AvatarPicker/AvatarPickerProfileView.swift @@ -87,9 +87,8 @@ struct AvatarPickerProfileView: View { extension AvatarPickerProfileView { private enum Localized { - static let viewProfileButtonTitle = NSLocalizedString( + static let viewProfileButtonTitle = SDKLocalizedString( "AvatarPickerProfile.Button.ViewProfile.title", - bundle: .module, value: "View profile →", comment: "Title of a button that will take you to your Gravatar profile, with an arrow indicating that this action will cause you to leave this view" ) diff --git a/Sources/GravatarUI/SwiftUI/AvatarPicker/AvatarPickerView.swift b/Sources/GravatarUI/SwiftUI/AvatarPicker/AvatarPickerView.swift index 5a55209a..1ef64287 100644 --- a/Sources/GravatarUI/SwiftUI/AvatarPicker/AvatarPickerView.swift +++ b/Sources/GravatarUI/SwiftUI/AvatarPicker/AvatarPickerView.swift @@ -313,29 +313,25 @@ private enum AvatarPicker { } enum Localized { - static let buttonUploadImage = NSLocalizedString( + static let buttonUploadImage = SDKLocalizedString( "AvatarPicker.ContentLoading.Success.ctaButtonTitle", - bundle: .module, value: "Upload image", comment: "Title of a button that allow for uploading an image" ) - static let buttonRetry = NSLocalizedString( + static let buttonRetry = SDKLocalizedString( "AvatarPicker.ContentLoading.Failure.Retry.ctaButtonTitle", - bundle: .module, value: "Try again", comment: "Title of a button that allows the user to try loading their avatars again" ) enum Header { - static let title = NSLocalizedString( + static let title = SDKLocalizedString( "AvatarPicker.Header.title", - bundle: .module, value: "Avatars", comment: "Title appearing in the header of a view that allows users to manage their avatars" ) - static let subtitle = NSLocalizedString( + static let subtitle = SDKLocalizedString( "AvatarPicker.Header.subtitle", - bundle: .module, value: "Choose or upload your favorite avatar images and connect them to your email address.", comment: "A message describing the purpose of this view" ) @@ -343,15 +339,13 @@ private enum AvatarPicker { enum ContentLoading { enum Success { - static let title = NSLocalizedString( + static let title = SDKLocalizedString( "AvatarPicker.ContentLoading.success.title", - bundle: .module, value: "Let's setup your avatar", comment: "Title of a message advising the user to setup their avatar" ) - static let subtext = NSLocalizedString( + static let subtext = SDKLocalizedString( "AvatarPicker.ContentLoading.Success.subtext", - bundle: .module, value: "Choose or upload your favorite avatar images and connect them to your email address.", comment: "A message describing the actions a user can take to setup their avatar" ) @@ -359,38 +353,33 @@ private enum AvatarPicker { enum Failure { enum SessionExpired { - static let title = NSLocalizedString( + static let title = SDKLocalizedString( "AvatarPicker.ContentLoading.Failure.SessionExpired.title", - bundle: .module, value: "Session expired", comment: "Title of a message advising the user that their login session has expired." ) enum Close { - static let buttonTitle = NSLocalizedString( + static let buttonTitle = SDKLocalizedString( "AvatarPicker.ContentLoading.Failure.SessionExpired.Close.buttonTitle", - bundle: .module, value: "Close", comment: "Title of a button that will close the Avatar Picker, appearing beneath a message that advises the user that their login session has expired." ) - static let subtext = NSLocalizedString( + static let subtext = SDKLocalizedString( "AvatarPicker.ContentLoading.Failure.SessionExpired.Close.subtext", - bundle: .module, value: "Sorry, it looks like your session has expired. Make sure you're logged in to update your Avatar.", comment: "A message describing the error and advising the user to login again to resolve the issue" ) } enum LogIn { - static let buttonTitle = NSLocalizedString( + static let buttonTitle = SDKLocalizedString( "AvatarPicker.ContentLoading.Failure.SessionExpired.LogIn.buttonTitle", - bundle: .module, value: "Log in", comment: "Title of a button that will begin the process of authenticating the user, appearing beneath a message that advises the user that their login session has expired." ) - static let subtext = NSLocalizedString( + static let subtext = SDKLocalizedString( "AvatarPicker.ContentLoading.Failure.SessionExpired.LogIn.subtext", - bundle: .module, value: "Session expired for security reasons. Please log in to update your Avatar.", comment: "A message describing the error and advising the user to login again to resolve the issue" ) @@ -398,15 +387,13 @@ private enum AvatarPicker { } enum Retry { - static let title = NSLocalizedString( + static let title = SDKLocalizedString( "AvatarPicker.ContentLoading.Failure.Retry.title", - bundle: .module, value: "Ooops", comment: "Title of a message advising the user that something went wrong while loading their avatars" ) - static let subtext = NSLocalizedString( + static let subtext = SDKLocalizedString( "AvatarPicker.ContentLoading.Failure.Retry.subtext", - bundle: .module, value: "Something went wrong and we couldn’t connect to Gravatar servers.", comment: "A message asking the user to try again" ) From c0127afb4006b5fcbe316f90fe7b801ab82e99ab Mon Sep 17 00:00:00 2001 From: Andrew Montgomery Date: Fri, 30 Aug 2024 14:15:39 -0500 Subject: [PATCH 4/9] Add SwiftLint support to SDK --- .swiftlint.yml | 8 ++++++++ .../xcshareddata/swiftpm/Package.resolved | 15 ++++++++++++--- Package.resolved | 11 ++++++++++- Package.swift | 9 +++++++-- 4 files changed, 37 insertions(+), 6 deletions(-) create mode 100644 .swiftlint.yml diff --git a/.swiftlint.yml b/.swiftlint.yml new file mode 100644 index 00000000..635fce65 --- /dev/null +++ b/.swiftlint.yml @@ -0,0 +1,8 @@ +only_rules: # Rules to run + - nslocalizedstring_require_bundle + +included: + - Sources + +# If true, SwiftLint will treat all warnings as errors. +strict: true diff --git a/Demo/Gravatar-Demo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Demo/Gravatar-Demo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index abd02be5..78bbb441 100644 --- a/Demo/Gravatar-Demo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Demo/Gravatar-Demo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "829ecc0bf847b439cbb46739f35d9014d6ce6f42eaa72db961e1c0c2d202fa8e", + "originHash" : "873e748e6cd0092c005bb2eeeb80dd830b1cffbb6a8974436ad78419281827e3", "pins" : [ { "identity" : "swift-snapshot-testing", @@ -15,8 +15,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-syntax", "state" : { - "revision" : "fa8f95c2d536d6620cc2f504ebe8a6167c9fc2dd", - "version" : "510.0.1" + "revision" : "6ad4ea24b01559dde0773e3d091f1b9e36175036", + "version" : "509.0.2" } }, { @@ -27,6 +27,15 @@ "revision" : "dd989a46d0c6f15c016484bab8afe5e7a67a4022", "version" : "0.54.0" } + }, + { + "identity" : "swiftlintplugins", + "kind" : "remoteSourceControl", + "location" : "https://github.com/SimplyDanny/SwiftLintPlugins", + "state" : { + "revision" : "6c3d6c32a37224179dc290f21e03d1238f3d963b", + "version" : "0.56.2" + } } ], "version" : 3 diff --git a/Package.resolved b/Package.resolved index f94ac4bb..f1e5bd25 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "85a761808437c26b26a29368f9cc9aa509cdd039f95eff656309c72fa6ff2557", + "originHash" : "2d82ed06a27431c1da79790f8b215b8abf6d2a7397f42f02e364c7a92f86a5ab", "pins" : [ { "identity" : "swift-snapshot-testing", @@ -27,6 +27,15 @@ "revision" : "dd989a46d0c6f15c016484bab8afe5e7a67a4022", "version" : "0.54.0" } + }, + { + "identity" : "swiftlintplugins", + "kind" : "remoteSourceControl", + "location" : "https://github.com/SimplyDanny/SwiftLintPlugins", + "state" : { + "revision" : "6c3d6c32a37224179dc290f21e03d1238f3d963b", + "version" : "0.56.2" + } } ], "version" : 3 diff --git a/Package.swift b/Package.swift index 979411bd..0431b86d 100644 --- a/Package.swift +++ b/Package.swift @@ -7,7 +7,9 @@ let package = Package( name: "Gravatar", defaultLocalization: "en", platforms: [ + // Platforms specifies os version minimums. It does not limit which platforms are supported. .iOS(.v15), + .macOS(.v12) // The SDK does not support macOS, this satisfies SwiftLint requirements ], products: [ // Products define the executables and libraries a package produces, making them visible to other packages. @@ -23,6 +25,7 @@ let package = Package( dependencies: [ .package(url: "https://github.com/nicklockwood/SwiftFormat", from: "0.54.0"), .package(url: "https://github.com/pointfreeco/swift-snapshot-testing", from: "1.8.1"), + .package(url: "https://github.com/SimplyDanny/SwiftLintPlugins", exact: "0.56.2"), ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. @@ -31,7 +34,8 @@ let package = Package( name: "Gravatar", swiftSettings: [ .enableExperimentalFeature("StrictConcurrency") - ] + ], + plugins: [.plugin(name: "SwiftLintBuildToolPlugin", package: "SwiftLintPlugins")] ), .testTarget( name: "GravatarTests", @@ -47,7 +51,8 @@ let package = Package( resources: [.process("Resources")], swiftSettings: [ .enableExperimentalFeature("StrictConcurrency") - ] + ], + plugins: [.plugin(name: "SwiftLintBuildToolPlugin", package: "SwiftLintPlugins")] ), .testTarget( name: "GravatarUITests", From 4342f8e47d9058c6bf0e9b62be56d8e6ee0af55a Mon Sep 17 00:00:00 2001 From: Andrew Montgomery Date: Wed, 4 Sep 2024 13:51:24 -0500 Subject: [PATCH 5/9] Add custom rule to detect use of NSLocalizedString --- .swiftlint.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.swiftlint.yml b/.swiftlint.yml index 635fce65..74aeb5af 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -1,8 +1,17 @@ only_rules: # Rules to run - - nslocalizedstring_require_bundle + - custom_rules included: - Sources # If true, SwiftLint will treat all warnings as errors. strict: true + +custom_rules: + no_ns_localized_string: + name: "No NSLocalizedString" + regex: "NSLocalizedString\\(" + match_kinds: + - identifier + message: "Use `SDKLocalizedString()` instead of `NSLocalizedString()`." + severity: error From 81c78140a2ef6a51fc11ef81e456cd9da170d058 Mon Sep 17 00:00:00 2001 From: Andrew Montgomery Date: Fri, 6 Sep 2024 13:16:38 -0500 Subject: [PATCH 6/9] Configure custom rule to check only the `Sources` folder (not the Demo source) --- .swiftlint.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.swiftlint.yml b/.swiftlint.yml index 74aeb5af..f4965dfa 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -1,14 +1,13 @@ only_rules: # Rules to run - custom_rules -included: - - Sources - # If true, SwiftLint will treat all warnings as errors. strict: true custom_rules: no_ns_localized_string: + included: + - "Sources/.*\\.swift" name: "No NSLocalizedString" regex: "NSLocalizedString\\(" match_kinds: From 50a6a886d95f1f84e799352562ffdb1ad6f13c0b Mon Sep 17 00:00:00 2001 From: Olivier Halligon Date: Mon, 9 Sep 2024 13:31:31 +0200 Subject: [PATCH 7/9] Allow SwiftPM plugin to be run on CI --- fastlane/Fastfile | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index f024b148..70a8ece2 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -14,6 +14,7 @@ XCODEPROJ_PATH = File.join(PROJECT_ROOT_FOLDER, 'Gravatar-Demo.xcodeproj') DEMO_APPS_SOURCES_FOLDER = File.join(PROJECT_ROOT_FOLDER, 'Demo') XCCONFIG_PROTOTYPE_BUILD_SWIFTUI = File.join(DEMO_APPS_SOURCES_FOLDER, 'Gravatar-SwiftUI-Demo', 'Gravatar-SwiftUI-Demo.Release.xcconfig') XCCONFIG_PROTOTYPE_BUILD_UIKIT = File.join(DEMO_APPS_SOURCES_FOLDER, 'Gravatar-UIKit-Demo', 'Gravatar-UIKit-Demo.Release.xcconfig') +COMMON_XCARGS = ['-skipPackagePluginValidation'] # Allow SwiftPM plugins (e.g. swiftlint) called from Xcode to be used on CI without prior manual approval GITHUB_REPO = 'Automattic/Gravatar-SDK-iOS' GITHUB_URL = "https://github.com/#{GITHUB_REPO}".freeze @@ -53,6 +54,7 @@ platform :ios do run_tests( package_path: '.', scheme: 'Gravatar-Package', + xcargs: COMMON_XCARGS, device: IPHONE_DEVICE, prelaunch_simulator: true, clean: true, @@ -65,10 +67,11 @@ platform :ios do lane :build_demo do |scheme: 'Gravatar-UIKit-Demo'| # We only need to build for testing to ensure that the project builds. # There are no tests in the the Demo apps - scan( + run_tests( project: XCODEPROJ_PATH, scheme: scheme, configuration: 'Debug', + xcargs: COMMON_XCARGS, device: IPHONE_DEVICE, clean: true, build_for_testing: true, @@ -88,9 +91,10 @@ platform :ios do configuration: 'Release', export_method: 'enterprise', output_directory: ARTIFACTS_FOLDER, - xcargs: { - CURRENT_PROJECT_VERSION: build_number - } + xcargs: [ + "CURRENT_PROJECT_VERSION=#{build_number}", + *COMMON_XCARGS + ] ) end From 5b379599c1d0e782480fe5dba4396581bab2d253 Mon Sep 17 00:00:00 2001 From: Olivier Halligon Date: Mon, 9 Sep 2024 13:37:24 +0200 Subject: [PATCH 8/9] Provide a custom name to Script Build phase Unrelated to this PR, but because I'm OCD and noticed that this same Build Phase had a custom name for one target of the Demo project but not the other --- Demo/Gravatar-Demo.xcodeproj/project.pbxproj | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Demo/Gravatar-Demo.xcodeproj/project.pbxproj b/Demo/Gravatar-Demo.xcodeproj/project.pbxproj index 0e00db8e..50d3be62 100644 --- a/Demo/Gravatar-Demo.xcodeproj/project.pbxproj +++ b/Demo/Gravatar-Demo.xcodeproj/project.pbxproj @@ -287,7 +287,7 @@ isa = PBXNativeTarget; buildConfigurationList = 49C5D6182B5B33E20067C2A8 /* Build configuration list for PBXNativeTarget "Gravatar SwiftUI" */; buildPhases = ( - 1E3FA23E2C74B808002901F2 /* ShellScript */, + 1E3FA23E2C74B808002901F2 /* Generate Secrets.swift */, 49C5D6062B5B33E20067C2A8 /* Sources */, 49C5D6072B5B33E20067C2A8 /* Frameworks */, 49C5D6082B5B33E20067C2A8 /* Resources */, @@ -385,7 +385,7 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 1E3FA23E2C74B808002901F2 /* ShellScript */ = { + 1E3FA23E2C74B808002901F2 /* Generate Secrets.swift */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -395,6 +395,7 @@ inputPaths = ( "$(SRCROOT)/Demo/Secrets.tpl", ); + name = "Generate Secrets.swift"; outputFileListPaths = ( ); outputPaths = ( From 3eae5b88937356bea9837e27cadc17b6bb8b864d Mon Sep 17 00:00:00 2001 From: Andrew Montgomery Date: Mon, 9 Sep 2024 16:03:59 -0500 Subject: [PATCH 9/9] Remove the `LocalizedString` typealias --- Sources/GravatarUI/Utility/SDKLocalizedString.swift | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/Sources/GravatarUI/Utility/SDKLocalizedString.swift b/Sources/GravatarUI/Utility/SDKLocalizedString.swift index ff352be7..fe5b13af 100644 --- a/Sources/GravatarUI/Utility/SDKLocalizedString.swift +++ b/Sources/GravatarUI/Utility/SDKLocalizedString.swift @@ -1,15 +1,5 @@ import Foundation -/// Use this to express *intent* on your API that the string you are manipulating / returning is intended to already be localized -/// and its value to have been provided via a call to `NSLocalizedString` or `SDKLocalizedString`. -/// -/// Semantically speaking, a method taking or returning a `LocalizedString` is signaling that you can display said UI string -/// to the end user, without the need to be treated as a key to be localized. The string is expected to already have been localized -/// at that point of the code, via a call to `NSLocalizedString`, `SDKLocalizedString` or similar upstream in the code. -/// -/// - Note: Remember though that, as a `typealias`, this won't provide any compile-time guarantee. -typealias LocalizedString = String - /// Use this function instead of `NSLocalizedString` to reference localized strings **from the library module**. /// /// You should use this `SDKLocalizedString` method in place of `NSLocalizedString` for all localized strings in the SDK. @@ -34,6 +24,6 @@ typealias LocalizedString = String /// - Returns: A localized version of the string designated by `key` in the table identified by `tableName`. /// If the localized string for `key` cannot be found within the table, `value` is returned. /// (However, `key` is returned instead when `value` is `nil` or the empty string). -func SDKLocalizedString(_ key: String, tableName: String? = nil, value: String? = nil, comment: String) -> LocalizedString { +func SDKLocalizedString(_ key: String, tableName: String? = nil, value: String? = nil, comment: String) -> String { Bundle.module.localizedString(forKey: key, value: value, table: tableName) }