Manages localization and shared resources. Use when adding localized strings, working with String extensions, adding translations, or configuring the Resources module.
Guide for the Resources module: localization and shared resources.
The Resources module provides app-specific resources used across features:
String.localized() extensionBundle.module accessor for resourcesLocation: Shared/Resources/
Note: Shared modules are app-specific (not reusable across apps), unlike Libraries which are generic and reusable.
| Language | Code | Status |
|---|
| English | en | Source language |
| Spanish | es | Fully translated |
The app uses .xcstrings format (Apple's modern localization format for iOS 16+).
Structure:
Shared/Resources/
├── Package.swift
├── Sources/
│ ├── Extensions/
│ │ └── String+Localized.swift # localized() extension
│ └── Resources/
│ └── Localizable.xcstrings
└── Tests/
All localized strings are centralized in the Resources module.
Location: Shared/Resources/Sources/Resources/Localizable.xcstrings
The localized() extension converts string keys to localized values:
// Shared/Resources/Sources/Extensions/String+Localized.swift
public extension String {
func localized() -> String {
Bundle.module.localizedString(forKey: self, value: nil, table: nil)
}
func localized(_ arguments: CVarArg...) -> String {
String(format: localized(), arguments: arguments)
}
}
Why this pattern? It allows type-safe, reusable localization without repeating bundle references. Translations are managed manually in .xcstrings files.
Each View defines a private LocalizedStrings enum that uses localized():
import {AppName}Resources
struct MyView: View {
var body: some View {
Text(LocalizedStrings.title)
}
}
// MARK: - LocalizedStrings
private enum LocalizedStrings {
static var title: String { "myView.title".localized() }
static var subtitle: String { "myView.subtitle".localized() }
static func itemCount(_ count: Int) -> String {
"myView.itemCount %lld".localized(count)
}
}
Shared/Resources/Sources/Resources/Localizable.xcstringsLocalizedStrings enum| Pattern | Example |
|---|---|
{screen}.{element} | home.title |
{screen}.{section}.{element} | characterList.empty.title |
common.{element} | common.tryAgain |
SPM automatically generates Bundle.module for targets that declare resources in their Package.swift. No manual Bundle+Module.swift is needed.
Used by: String.localized() to access Localizable.xcstrings.
The main app must declare supported languages in Project.swift via CFBundleLocalizations:
// Project.swift
let appInfoPlist: [String: Plist.Value] = [
"CFBundleLocalizations": ["en", "es"],
// ...
]
Important: iOS does not load localizations from embedded frameworks unless the main app declares supported languages in
CFBundleLocalizations. Without this configuration, the app will always display the development language (English) regardless of device settings.
Localizable.xcstrings in XcodeCFBundleLocalizations in Project.swift:
"CFBundleLocalizations": ["en", "es", "NEW_LANG_CODE"],
./Scripts/generate.shLocalizable.xcstrings with all translationsLocalizedStrings enumlocalized() or localized(_:) for interpolationLocalizable.xcstrings in XcodeCFBundleLocalizations in Project.swift./Scripts/generate.sh