A Swift macro that automatically generates localized string properties for enums, making internationalization in Swift projects more type-safe and maintainable.
- Type-safe localization: Convert enum cases to localization keys automatically
- Multiple key formats: Support for upper snake case, lower snake case, camel case, and Pascal case
- String formatting: Automatic handling of associated values for string interpolation
- Bundle support: Custom bundle support for modular apps
- Compile-time validation: Detect key conflicts and invalid usage at compile time
- Zero runtime overhead: All code is generated at compile time
Add the following dependency to your Package.swift:
dependencies: [
.package(url: "https://github.com/EyalKatz24/Localized.git", from: "1.0.0")
]Or add it to your Xcode project:
- File → Add Package Dependencies
- Enter the repository URL
- Select the version you want to use
Simply add the @Localized macro to any enum:
@Localized
enum Localization {
case ok
case cancel
case welcome
case goodbye
}This generates:
- A
localizedproperty that returns the localized string - A
localizedKeyproperty that returns the localization key - A private
localized(_:)function for internal use
The macro automatically handles associated values for string formatting:
@Localized
enum Localization {
case welcome(name: String)
case totalCost(amount: Double, currency: String)
case items(count: Int, itemName: String)
}You can customize how enum cases are converted to localization keys:
// Upper snake case (default): HELLO_WORLD
@Localized
enum Localization {
case helloWorld
}
// Lower snake case: hello_world
@Localized(keyFormat: .lowerSnakeCase)
enum Localization {
case helloWorld
}
// Camel case: helloWorld
@Localized(keyFormat: .camelCase)
enum Localization {
case helloWorld
}
// Pascal case: HelloWorld
@Localized(keyFormat: .pascalCase)
enum Localization {
case helloWorld
}For modular apps or frameworks, you can specify a custom bundle:
@Localized(bundleId: "com.myapp.core")
enum CoreLocalization {
case welcome
case error
}
// Or with both key format and bundle
@Localized(keyFormat: .camelCase, bundleId: "com.myapp.features")
enum FeatureLocalization {
case newFeature
case settings
}When using in a Swift Package, you can use Bundle.module:
@Localized(bundleId: "\(Bundle.module.bundleIdentifier!)")
enum PackageLocalization {
case packageSpecific
}The macro generates the following code for each enum:
@Localized
enum Localization {
case welcome(name: String)
case goodbye
// Generated properties and methods
public var localized: String {
switch self {
case let .welcome(value0):
String(format: localized("WELCOME"), value0)
case .goodbye:
localized("GOODBYE")
}
}
public var localizedKey: String {
switch self {
case .welcome:
"WELCOME"
case .goodbye:
"GOODBYE"
}
}
private func localized(_ string: String) -> String {
NSLocalizedString(string, comment: "")
}
}Create your .strings files with the generated keys:
Localizable.strings (English)
"OK" = "OK";
"CANCEL" = "Cancel";
"WELCOME" = "Welcome, %@!";
"TOTAL_COST" = "Total: %@ %@";
"ITEMS" = "%d %@";
Localizable.strings (Spanish)
"OK" = "Aceptar";
"CANCEL" = "Cancelar";
"WELCOME" = "¡Bienvenido, %@!";
"TOTAL_COST" = "Total: %@ %@";
"ITEMS" = "%d %@";
Instead of one large localization enum, consider organizing by feature:
@Localized
enum AuthLocalization {
case login
case logout
case invalidCredentials
}
@Localized
enum ProfileLocalization {
case editProfile
case saveChanges
case profileUpdated
}Make your enum cases descriptive and self-documenting:
// Good
case welcomeMessage(userName: String)
case paymentFailed(reason: String)
// Avoid
case wm(name: String)
case pf(reason: String)The macro automatically handles special characters and reserved words:
@Localized
enum Localization {
case `class` // Becomes "CLASS"
case `struct` // Becomes "STRUCT"
case `enum` // Becomes "ENUM"
case hello_world // Becomes "HELLO_WORLD"
}The macro provides compile-time validation for common issues:
@Localized(keyFormat: .pascalCase)
enum Localization {
case duplicate // Error: Key conflict with 'Duplicate'
case Duplicate
}@Localized // Error: Can only be attached to enums
struct Localization {
// ...
}- Swift 5.9+
- iOS 13.0+ / macOS 10.15+ / tvOS 13.0+ / watchOS 6.0+ / macCatalyst 13.0+
This project is licensed under the MIT License - see the LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.