How can I change the localization of the App on the fly in SwiftUI?
I think we can use below code, but we should find SwiftUI approach.
func localized(_ lang:String) -> String {
let path = Bundle.main.path(forResource: lang, ofType: "lproj")
let bundle = Bundle(path: path!)
return NSLocalizedString(self, tableName: nil, bundle: bundle!, value: "", comment: "")
}}
Exporting localizations Follow the steps below. In the Project navigator, choose the project, then Editor → Export for Localization. In the dialog box, enter a folder name, select a location where you want it exported, and uncheck English because we do not want to translate that, and finally, click Export.
In your project settings, go to Build Settings and search for Use compiler to Extract Swift Strings. Make sure to search All settings, not just the Basic ones. Change the value of this setting to Yes. In Xcode, go to Product ▸ Export Localizations….
To do this, in Xcode, select Product > Scheme > Manage Schemes ... Then in the Run/debug tab, change the "Application Language" to your desired language. And now every time you build and run your app from Xcode, it will use that language as the preferred language.
LocalizedStringKey is a special type that signals SwiftUI to look up localized strings in your bundle. Use it in custom SwiftUI views to make them ready for localization. Enable the "Use Compiler to Extract Swift Strings" build setting to extract LocalizedStringKeys from code when exporting for localization in Xcode.
First of all, we should create 2 Localizable.strings
files, in my case it's en and ru.
And we should store our current language object, I choose store it property in UserSettings
like ObservableObject
class UserSettings: ObservableObject {
@Published var lang: String = "ru"
var bundle: Bundle? {
let b = Bundle.main.path(forResource: lang, ofType: "lproj")!
return Bundle(path: b)
}
}
We can use this settings object like .environmentObject()
in SceneDelegate.swift
, so every view in hierarchy will be updated.
var settings = UserSettings()
// ...
= UIHostingController(rootView: contentView.environmentObject(settings))
In View
we can get desirable behaviour, note we should specify bundle
in Text
initialization.
struct ContentView: View {
@EnvironmentObject var settings: UserSettings
var body: some View {
VStack {
Text("App", bundle: settings.bundle)
}
}
}
And now I can change the language on someplace in the app, here is just sample loop example, you can call this function changeLanguage()
in the of scene(_ scene:, willConnectTo:, options connectionOptions:)
and every 3 seconds language will be changed.
func changeLanguage() {
print(#function)
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
self.settings.lang = self.settings.lang == "ru" ? "en" : "ru"
self.changeLanguage()
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With