0

I watched the talk at WWDC25 where Apple introduced the generated symbols feature for Strings Catalog.

Since I have just started a new project as my first iOS development experience (I come from 10+ experience in Android), I found this feature very neat considering how it was done in the past.

Anyway, I started implementing my very first string for English & French (my native tongue). The project is setup to use English as the default language.

My project is decoupled into multiple targets (simple swift frameworks) and in my View target, where I am writing the UI code, I have created a resource folder in which I created the Strings Catalog which content is a follow:

{ "sourceLanguage" : "en", "strings" : { "loading data" : { "extractionState" : "manual", "localizations" : { "en" : { "stringUnit" : { "state" : "translated", "value" : "Loading data..." } }, "fr" : { "stringUnit" : { "state" : "translated", "value" : "Chargement des données..." } } } } }, "version" : "1.1" } 

And in the code:

public struct HomeScreen: View { public init(){} @StateObject private var viewModel: HomeViewModel = Resolver.resolve() public var body: some View { content } @ViewBuilder private var content: some View { switch(viewModel.uiState) { case .loading: ProgressView(String(localized: .HomeScreenStrings.loadinData)) .frame(maxWidth: .infinity, maxHeight: .infinity) .background(Color(.systemBackground)) ... // other cases } } 

When building the app on my iPhone X - iOS 16 (the minimum supported by the app), the displayed text is in English. But my iPhone is setup French...


If I switch to French as the default language in Project > Infos > Localizations, the french text is properly displayed which at least confirm the catalog is properly bundled in my app. By the way, both language (FR / EN) are listed in the project main Infos.plist.

I also made sure to add the 2 supported languages in the Infos.plist of my View target:

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CFBundleLocalizations</key> <array> <string>en</string> <string>fr</string> </array> </dict> </plist> 

But in Xcode it also shows that Default Localization is set to "$(DEVELOPMENT_LANGUAGE)". I don't know if that matters somehow?

Finally, if I print the preferred language of my device:

print(Locale.preferredLanguages) 

it get: ["fr"].

And there you have it. I don't how to fix that. Am I doing something wrong?

2
  • Do you have any xcstrings file in the main target? I believe you need to add at least one key and translation for French in the main target for the OS to know that the app is available in French. Locale.preferredLanguages is not relevant here. Look at the value of Locale.current instead. Commented Nov 3 at 9:48
  • yes, I did create a String Catalog in my main app's target, just as I reported it in my comment stackoverflow.com/questions/79807357/…. So I inadvertently fixed the issue! Kudos to you to find out the real solution, which I have validated. Commented Nov 3 at 10:32

1 Answer 1

1

In your main target, you should also add a Localizable.xcstrings file with at least one key and translation for French. Otherwise, iOS will not know that your app is also available French. This can be seen from this setting:

enter image description here

There will not be a "French" option if your app's main target does not have at least one translation for French. Crucially, Locale.current will return an English locale. The generated LocalizedStringResources will use Locale.current to localise.

So, all you need to do is to add a French translation in the main target's Localizable.xcstrings file. The key doesn't need to be used anywhere.

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks @sweeper for helping out again. Based on your answer, it seems I'd have to revert back to using hard-coded strings, thus loosing the advantage of generated symbols that Xcode 26 brings with Strings Catalog. For instance, if I try Text(.HomeScreenStrings.loadingData, bundle: Bundle(for: ViewBundleFinder.self)), I get the error "Type 'LocalizedStringKey' has no member 'HomeScreenStrings'". And if I try ProgressView(Text("loading data", bundle: Bundle(for: ViewBundleFinder.self))), I get "Initializer 'init(_:)' requires that 'Text' conform to 'StringProtocol'".
Sorry, I made a mistake for the second part of the comment. The follow code works based on your answer: ProgressView {Text("loading data", bundle: Bundle(for: ViewBundleFinder.self))}. But as I said before, I loose the advantage of generic symbols. Do you think that using Swift Package could make it work ?
@Mackovich Oh, you are using the LocalizedStringResources! Sorry I was confused. Xcode should be generating those with the correct bundle. Can you edit your question with the generated source file? I cannot reproduce the problem.
I don't seem to be able to find the generated source file of the LocalizedStrings. My View framework is quite empty at the moment as in the Finder I can only see HomeScreenStrings.xcstrings (which I already gave the content in the OP), Info.plist and HomeScreen.swift.
Also, I tried creating a String Catalog in the main target (the app's target) with one key, both in FR / ENG and display it in a ProgressView and it does work as intended. Now, I wonder how can I make it work in a framework. Hence my question: will it work if I convert it to Swift Package? The problem with that, I would have to convert all my frameworks (Presentation / Domain / Data) into Swift Packages and it seems these are generated as separate projects that I have to manually copy & paste onto my app's project based on that video: youtube.com/watch?v=jnv3K0mbIDo
your last suggestion could have been the solution. But I cannot test it again to make sure, because when I did create a local strings catalog to my app's main target, my HomeScreen finally started to display the right language and it shows French in the app settings on iOS 16. But it any case, I'll validate your answer. Thanks again!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.