The word “locale” should not be used here at all, because locales do not come into play at all. Open Xcode, create a new project and use the UI to create add a localization. Every multi‐component localization it suggests uses a hyphen, not an underscore. The resulting subdirectory name also has a hyphen, not an underscore. This is because they are IETF language tags, and they have absolutely nothing to do with Foundation
’s Locale
type or its POSIX identifiers. Many simple identifiers can be easily converted back and forth by swapping hyphens for underscores and vice versa, but more complex ones do not map at all.
To be abundantly clear, the underscored examples currently in the proposal are incompatible with Foundation
, and will not always work properly with the macOS System Preferences. [Edit: I did some experimenting and it appears macOS attempts to handle both types of identifiers if I manually set them arbitrarily with the defaults
command line tool. I presume this is for legacy or compatibility reasons. But both System Preferences and Xcode generate IETF‐style hyphenated identifiers. And the POSIX identifiers break down when they get more complicated, while the IETF ones work no matter what.]
The static constants are shown on an extension in the proposal. Is that supposed to be an extension to Foundation
’s Locale
type? If so, it is the wrong type for the job. SwiftPM should either roll its own Localization
type, or just use strings like the Foundation
API (such as here, here, or here).
Yeah, I guess that would be annoying for unlocalized packages. Then I propose making it optional, nil
by default and then throw an error if the manifest forgets it but still tries to use resources.
Interesting. To what extent is Info.plist
understood on other platforms? Handling of Info.plist
probably needs to be flushed out more. A lot more goes into Info.plist
than localization. How should the mix of user‐defined parts and SwiftPM‐defined parts be juggled?
In the most common scenario, SwiftPM will be making a resource bundle, and the client application will have its own development region specified, thereby overriding anything specified by the embedded bundle. It only comes into play in the rare case that the resource bundle does not support a localization used by the top level application, and then no option is really all that good.
Actually, I just looked at the source code, and it does not look like it comes into play at all (whether intentionally or by accident). Bundle
’s preferredLocalizations(from:)
calls CFBundleCopyPreferredLocalizationsFromArray
, which forwards to _CFBundleCopyLocalizationsForPreferences
, which forwards to _CFBundleCopyPreferredLanguagesInList
, with devLang
as simply NULL
. That last function then ignores it and falls back to US English.
Since it does nothing anyway, can we drop the idea of a development region and punt it along with Info.plist
until the point were SwiftPM is trying to handle top‐level bundled applications (if ever)? In a main bundle like that is the only case were CFBundleDevelopmentRegion
would have any effect. (Finder might also use it as a fallback if the bundle had a localized display name, but (a) it is embedded inside another bundle and (b) SwiftPM isn’t attempting to support CFBundleDisplayName
yet.)
I think that will only make the dangerous conflation even worse in developer’s minds. CoreFoundation
’s own source code already testifies to how widespread the confusion is. Xcode’s GUI displays full English names of each of its suggestions, and those could be used if we really want constants. But to be honest, I’m not really convinced that 930 constants are worth their weight when the user needs to know the code anyway to create the directory.
I also assume the declaration will need to match the directory exactly. What happens if you have "en_US"
in the manifest, but "en-US.lproj"
in the file system? Or "ar"
and "ara.lproj"
? Or "cze"
and "ces.lproj"
? (All three pairs are semantically equal.) How much responsibility for such things does SwiftPM want to take on? If we just take a string, then we don’t have to worry about it and can let it be the user’s problem. But if the actual string identifier is hidden behind a constant name, it will make debugging such situations all the more confusing.