-
Notifications
You must be signed in to change notification settings - Fork 135
Localization: Phase 2 - public API #2477
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
atmamont
merged 13 commits into
feature/cosdk-1097-ios-v6-custom-localization-develop
from
feature/cosdk-1097-ios-v6-custom-localization-phase2
Apr 20, 2026
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
35ce516
feat: introduce CheckoutLocalizationKey, CheckoutLocalizationProvider…
atmamont 5263346
feat: propagate localizationProvider through CheckoutComponentBuilder…
atmamont c510cca
test: add unit tests for localizationProvider storage and propagation
atmamont c0911f2
demo: add DemoLocalizationProvider to CardComponentAdvancedFlowExampl…
atmamont a98c8dc
Deduplicate package and public localization key enums and keep one in…
atmamont a0b35da
swiftlint: Increase identifier lenght to 60 characters to match Andro…
atmamont 6369a92
Code cleanup
atmamont 8a176ae
Merge branch 'feature/cosdk-1097-ios-v6-custom-localization-develop' …
atmamont 71f079a
Improve the code, restore comments
atmamont 2542366
Disable swiftline rule in a single block instead of changing the rule…
atmamont 6e7e383
Add code docs for new public interface
atmamont 999afee
Replace enum-based i18n key with struct-based namespace to prevent an…
atmamont c868cee
Add “xcstrings” to spellcheck allowlist
atmamont File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,137 @@ | ||
| // | ||
| // Copyright (c) 2026 Adyen N.V. | ||
| // | ||
| // This file is open source and available under the MIT license. See the LICENSE file for more info. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| // Key set mirrors the Android SDK `CheckoutLocalizationKey` enum for cross-platform alignment. | ||
| // Android: https://github.com/Adyen/adyen-android/blob/main/core/src/main/java/com/adyen/checkout/core/common/localization/CheckoutLocalizationKey.kt | ||
| /// A localization key passed to ``CheckoutLocalizationProvider``. | ||
| /// | ||
| /// Compare against the well-known static members (e.g. `.cardNumber`) to identify which | ||
| /// string the SDK is requesting. New keys may be added in future SDK versions — always | ||
| /// include a `default` branch when switching over values. | ||
| public struct CheckoutLocalizationKey: Hashable { | ||
|
|
||
| /// The internal ``LocalizationKey`` used for SDK string resolution. | ||
| internal let localizationKey: LocalizationKey | ||
|
|
||
| internal init(localizationKey: LocalizationKey) { | ||
| self.localizationKey = localizationKey | ||
| } | ||
|
|
||
| /// Creates a key that has no direct ``LocalizationKey`` counterpart, | ||
| /// identified by its camelCase name within the `checkout.*` namespace. | ||
| internal init(name: String) { | ||
| localizationKey = LocalizationKey(key: "checkout.\(name)") | ||
| } | ||
|
|
||
| public static func == (lhs: Self, rhs: Self) -> Bool { | ||
| lhs.localizationKey.key == rhs.localizationKey.key | ||
| } | ||
|
|
||
| public func hash(into hasher: inout Hasher) { | ||
| hasher.combine(localizationKey.key) | ||
| } | ||
| } | ||
|
|
||
| // swiftlint:disable identifier_name | ||
|
|
||
| // MARK: - General | ||
|
|
||
| extension CheckoutLocalizationKey { | ||
| public static let generalBack = CheckoutLocalizationKey(name: "generalBack") | ||
| public static let generalCancel = CheckoutLocalizationKey(localizationKey: .cancelButton) | ||
| public static let generalClose = CheckoutLocalizationKey(name: "generalClose") | ||
| public static let generalOptional = CheckoutLocalizationKey(localizationKey: .fieldTitleOptional) | ||
| public static let generalSearchHint = CheckoutLocalizationKey(localizationKey: .searchPlaceholder) | ||
| } | ||
|
|
||
| // MARK: - Card | ||
|
|
||
| extension CheckoutLocalizationKey { | ||
| public static let cardNumber = CheckoutLocalizationKey(localizationKey: .cardNumberItemTitle) | ||
| public static let cardNumberInvalid = CheckoutLocalizationKey(localizationKey: .cardNumberItemInvalid) | ||
| public static let cardNumberInvalidUnsupportedBrand = CheckoutLocalizationKey(localizationKey: .cardNumberItemUnsupportedBrand) | ||
| public static let cardExpiryDate = CheckoutLocalizationKey(localizationKey: .cardExpiryItemTitle) | ||
| public static let cardExpiryDateHint = CheckoutLocalizationKey(localizationKey: .cardExpiryItemPlaceholder) | ||
| public static let cardExpiryDateInvalid = CheckoutLocalizationKey(localizationKey: .cardExpiryItemInvalid) | ||
| public static let cardExpiryDateInvalidTooOld = CheckoutLocalizationKey(name: "cardExpiryDateInvalidTooOld") | ||
| public static let cardExpiryDateInvalidTooFarInTheFuture = CheckoutLocalizationKey(name: "cardExpiryDateInvalidTooFarInTheFuture") | ||
| public static let cardSecurityCode = CheckoutLocalizationKey(localizationKey: .cardCvcItemTitle) | ||
| public static let cardSecurityCodeHint3Digits = CheckoutLocalizationKey(name: "cardSecurityCodeHint3Digits") | ||
| public static let cardSecurityCodeHint4Digits = CheckoutLocalizationKey(name: "cardSecurityCodeHint4Digits") | ||
| public static let cardSecurityCodeInvalid = CheckoutLocalizationKey(localizationKey: .cardCvcItemInvalid) | ||
| public static let cardHolderName = CheckoutLocalizationKey(localizationKey: .cardNameItemTitle) | ||
| public static let cardHolderNameInvalid = CheckoutLocalizationKey(localizationKey: .cardNameItemInvalid) | ||
| public static let cardStorePaymentMethod = CheckoutLocalizationKey(localizationKey: .cardStoreDetailsButton) | ||
| public static let cardDualBrandSelectorTitle = CheckoutLocalizationKey(localizationKey: .creditCardDualBrandTitle) | ||
| public static let cardDualBrandSelectorDescription = CheckoutLocalizationKey(localizationKey: .creditCardDualBrandDescription) | ||
| public static let cardSocialSecurityNumber = CheckoutLocalizationKey(name: "cardSocialSecurityNumber") | ||
| public static let cardSocialSecurityNumberInvalid = CheckoutLocalizationKey(name: "cardSocialSecurityNumberInvalid") | ||
| } | ||
|
|
||
| // MARK: - Drop-in | ||
|
|
||
| extension CheckoutLocalizationKey { | ||
| public static let dropInManageFavoritesTitle = CheckoutLocalizationKey(name: "dropInManageFavoritesTitle") | ||
| public static let dropInManageFavoritesCardsSectionTitle = CheckoutLocalizationKey(name: "dropInManageFavoritesCardsSectionTitle") | ||
| public static let dropInManageFavoritesOthersSectionTitle = CheckoutLocalizationKey(name: "dropInManageFavoritesOthersSectionTitle") | ||
| public static let dropInManageFavoritesRemove = CheckoutLocalizationKey(name: "dropInManageFavoritesRemove") | ||
| public static let dropInManageFavoritesRemoveConfirmation = CheckoutLocalizationKey(name: "dropInManageFavoritesRemoveConfirmation") | ||
| public static let dropInOtherPaymentMethods = CheckoutLocalizationKey(name: "dropInOtherPaymentMethods") | ||
| public static let dropInPaymentMethodListDescription = CheckoutLocalizationKey(name: "dropInPaymentMethodListDescription") | ||
| // swiftlint:disable:next line_length | ||
| public static let dropInPaymentMethodListFavoritesSectionTitle = CheckoutLocalizationKey(name: "dropInPaymentMethodListFavoritesSectionTitle") | ||
| // swiftlint:disable:next line_length | ||
| public static let dropInPaymentMethodListFavoritesSectionAction = CheckoutLocalizationKey(name: "dropInPaymentMethodListFavoritesSectionAction") | ||
| // swiftlint:disable:next line_length | ||
| public static let dropInPaymentMethodListOptionsSectionTitle = CheckoutLocalizationKey(name: "dropInPaymentMethodListOptionsSectionTitle") | ||
| // swiftlint:disable:next line_length | ||
| public static let dropInPaymentMethodListOptionsTitleWithFavorites = CheckoutLocalizationKey(name: "dropInPaymentMethodListOptionsTitleWithFavorites") | ||
| public static let dropInPaymentMethodCardDescription = CheckoutLocalizationKey(name: "dropInPaymentMethodCardDescription") | ||
| } | ||
|
|
||
| // MARK: - Await | ||
|
|
||
| extension CheckoutLocalizationKey { | ||
| public static let awaitLoading = CheckoutLocalizationKey(localizationKey: .awaitWaitForConfirmation) | ||
| } | ||
|
|
||
| // MARK: - MBWay | ||
|
|
||
| extension CheckoutLocalizationKey { | ||
| public static let mbwayCountryCode = CheckoutLocalizationKey(name: "mbwayCountryCode") | ||
| public static let mbwayInvalidPhoneNumber = CheckoutLocalizationKey(name: "mbwayInvalidPhoneNumber") | ||
| public static let mbwayPhoneNumber = CheckoutLocalizationKey(name: "mbwayPhoneNumber") | ||
| } | ||
|
|
||
| // MARK: - BLIK | ||
|
|
||
| extension CheckoutLocalizationKey { | ||
| public static let blikCode = CheckoutLocalizationKey(localizationKey: .blikCode) | ||
| public static let blikCodeHint = CheckoutLocalizationKey(name: "blikCodeHint") | ||
| public static let blikCodeInvalid = CheckoutLocalizationKey(localizationKey: .blikInvalid) | ||
| public static let blikHelperText = CheckoutLocalizationKey(localizationKey: .blikHelp) | ||
| } | ||
|
|
||
| // swiftlint:enable identifier_name | ||
|
|
||
| /// An interface for providing selective programmatic overrides of Adyen Checkout UI strings. | ||
| /// | ||
| /// Use this provider when you need to override a small number of strings. | ||
| /// Return a non-`nil` value only for the keys you want to override; | ||
| /// returning `nil` will let the SDK apply its normal localization fallback chain. | ||
| /// | ||
| /// ## Adding support for a completely new language | ||
| /// This protocol is not the recommended path for adding a language that the SDK does not ship. | ||
| /// Instead, place a `.strings` or `.xcstrings` file in your app bundle with the `adyen.*` keys | ||
| /// translated into the target language. The SDK resolves strings from `Bundle.main` first, | ||
| /// so your translations are picked up automatically with no provider required. | ||
| /// | ||
| // TODO: Provide reference doc/link to the file with all SDK keys | ||
| public protocol CheckoutLocalizationProvider { | ||
| func localizedString(_ key: CheckoutLocalizationKey, locale: Locale) -> String? | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.