Skip to content

[Proposal]: #bundle macro #1251

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
merged 3 commits into from
Apr 28, 2025
Merged

Conversation

Tantalum73
Copy link
Contributor

This proposal adds a macro to find the bundle that contains resources useful for the current context: #bundle.

@Tantalum73 Tantalum73 changed the title #bundle macro [Proposal]: #bundle macro Apr 15, 2025
@itingliu
Copy link
Contributor

@swift-ci please test

# Introduce `#bundle`


* Proposal: [SF-NNNN](NNNN-filename.md)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Proposal: [SF-NNNN](NNNN-filename.md)
* Proposal: [SF-0024](NNNN-filename.md)

@itingliu
Copy link
Contributor

@swift-ci please test


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
Copy link
Contributor

@stmontgomery stmontgomery Apr 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example of localized resources in a framework or library is a solid motivator for this feature. But if you're interested in citing other motivators, I have one to suggest:

Swift Testing allows and recommends using structs (value types) instead of classes for grouping related test functions. Often, test authors need to reference resources in their test bundle for things like fixture data files. Historically it has been straightforward to use Bundle(forClass:) and pass the XCTestCase subclass in the current file to accomplish this. But when using Swift Testing idiomatically, users may not have a class in the test bundle module which can conveniently serve this purpose. And of course, as its name implies, Bundle(forClass:) does require a class meta type and doesn't accept the type of a struct. So this feature will benefit Swift Testing users and allow them to use value types for suites even more easily.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I mean Bundle.init(for:) which accepts AnyClass, but you get the idea.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great example, I haven't thought about Swift Testing!

extension LocalizedStringResource {
@_alwaysEmitIntoClient
@_disfavoredOverload
public init(_ keyAndValue: String.LocalizationValue, table: String? = nil, locale: Locale = .current, bundle: Bundle, comment: StaticString? = nil)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason these couldn't declare a default value of #bundle for the bundle: parameter now, in this proposal, leveraging SE-0422 immediately? I see that mentioned in Alternatives Considered, but it's unclear why it couldn't or shouldn't be done now when this new extension is being introduced.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for bringing this up!

The other existing, similar initializer to this one is this:

LocalizedStringResource(
    _ keyAndValue: String.LocalizationValue,     
    table: String? = nil,     
    locale: Locale = .current,     
    bundle: LocalizedStringResource.BundleDescription = .main,     
    comment: StaticString? = nil
)

If our new initializer only took parameters with default values, one had to be marked as disfavored, probably the new one:

@_disfavoredOverload
LocalizedStringResource(
    _ keyAndValue: String.LocalizationValue, 
    table: String? = nil, 
    locale: Locale = .current, 
    bundle: Bundle = #bundle, 
    comment: StaticString? = nil
)

With the new initializer being disfavored, its default value would never take effect: LocalizedStringResource("Hello") always uses the existing initializer, and its default values, but never the new initializer (with its default values).
To use the new initializer, one has to write LocalizedStringResource("Hello", bundle: <...>), in which case a default value for bundle doesn't matter.

As eluded to in Future Directions, we can't change the default value for all bundle: parameters this year. For consistency's sake, and because a default value here wouldn't apply anyway, I think it's better to not default anything to #bundle for now.

@itingliu itingliu merged commit f405ad1 into swiftlang:main Apr 28, 2025
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants