Hi everyone!
We have a new pitch to introduce a macro that finds the correct bundle where resources are located: #bundle
. In the context of a Swift Package, it will use Bundle.module
, in a framework it will point to the framework's bundle, and in the main app, it will be equivalent to Bundle.main
.
Let us know what you think!
- Proposal: SF-NNNN
- Authors: Matt Seaman, Andreas Neusuess
- Review Manager: TBD
- Status: Awaiting review
Revision history
- v1 Initial version
Introduction
API which loads localized strings assumes Bundle.main
by default. This works for apps, but code that runs in a framework, or was defined in a Swift package, needs to specify a different bundle. The ultimate goal is to remove this requirement in the future. One step towards that goal is to provide an easy accessor to the bundle that stores localized resources: #bundle
.
Motivation
Developers writing code in a framework or a Swift package need to repeat the bundle
parameter for every localized string.
Without any shortcuts, loading a localized string from a framework looks like this:
label.text = String(
localized: "She didn't clean the camera!",
bundle: Bundle(for: MyViewController.self),
comment: "Comment of astonished bystander"
)
Because of its impracticalities, developers often write accessors to the framework's bundle:
private class LookupClass {}
extension Bundle {
static let framework = Bundle(for: LookupClass.self)
// Or worse yet, they lookup the bundle using its bundle identifier, which while tempting is actually rather inefficient.
}
label.text = String(
localized: "She didn't clean the camera!",
bundle: .framework,
comment: "Comment of astonished bystander"
)
While this solution requires less boilerplate, each framework target has to write some boilerplate still.
In the context of a localized Swift package, the build system takes care of creating an extension on Bundle
called Bundle.module
at build time. While this reduces the need for boilerplate already, it makes it complicated to move code from a framework or app target into a Swift package. Each call to a localization API needs to be audited and changed to bundle: .module
.
Proposed solution and example
We propose a macro that handles locating the right bundle with localized resources. It will work in all contexts: apps, framework targets, and Swift packages.
label.text = String(
localized: "She didn't clean the camera!",
bundle: #bundle,
comment: "Comment of astonished bystander"
)
We will also introduce an equivalent macro for usage with LocalizedStringResource.BundleDescription
.
let string = LocalizedStringResource(
"She didn't clean the camera!",
bundle: #bundleDescription,
comment: "Comment of astonished bystander"
)
For a full detailed design and considered alternatives, check out thefull proposal in the swift-foundation repo PR!