We have lined iOS localization in a number of tutorials, together with one which exhibits easy methods to totally localize an app utilizing String Catalogs. Nevertheless, these tutorials depend on the system language to find out the app’s language. However what if you wish to give customers the flexibility to decide on their most well-liked language, whatever the system setting? And what in order for you the language to replace immediately—with out restarting the app? That’s precisely what this tutorial will train you.
Earlier than we get began, I like to recommend reviewing the sooner iOS localization tutorial when you’re not conversant in String Catalogs. The demo app used on this tutorial builds on the one from that information.
The Demo App

We’re reusing the demo app from our iOS localization tutorial—a easy app with fundamental UI components for example localization ideas. On this tutorial, we’ll prolong it by including a Settings display that lets customers choose their most well-liked language. The app will then replace the language immediately, without having to restart.
Including App Languages and App Settings
Earlier than we begin constructing the Setting display, let’s first add an AppLanguage
enum and an AppSetting
class to the undertaking. The AppLanguage
enum defines the set of languages that your app helps. Right here is the code:
enum AppLanguage: String, CaseIterable, Identifiable {
case en, fr, jp, ko, zhHans = "zh-Hans", zhHant = "zh-Hant"
var id: String { rawValue }
var displayName: String {
swap self {
case .en: return "English"
case .fr: return "French"
case .jp: return "Japanese"
case .ko: return "Korean"
case .zhHans: return "Simplified Chinese language"
case .zhHant: return "Conventional Chinese language"
}
}
}
Every case within the enum corresponds to a particular language, utilizing customary locale identifiers as uncooked values. For instance, .en
 maps to "en"
 for English, .fr
 to "fr"
 for French, and so forth. The displayName
 computed property offers a user-friendly label for every language. As an alternative of displaying uncooked locale codes like “en” or “zh-Hans” within the UI, this property returns readable names resembling “English” or “Simplified Chinese language.”
The AppSetting
class, which conforms to the ObservableObject
protocol, is a straightforward observable mannequin that shops the person’s chosen language. Right here is the code:
class AppSetting: ObservableObject {
@Revealed var language: AppLanguage = .en
}
By default, the language is ready to English. Later, when the person selects a distinct language from the Settings display, updating this property will trigger SwiftUI views that depend on the app’s locale to re-render utilizing the brand new language.
Constructing the Setting Display

Subsequent, let’s construct the Settings display. It’s a easy interface that shows a listing of all of the supported languages. Under is the code for implementing the setting view:
struct SettingView: View {
@Atmosphere(.dismiss) var dismiss
@EnvironmentObject var appSetting: AppSetting
@State non-public var selectedLanguage: AppLanguage = .en
var physique: some View {
NavigationStack {
Kind {
Part(header: Textual content("Language")) {
ForEach(AppLanguage.allCases) { lang in
HStack {
Textual content(lang.displayName)
Spacer()
if lang == selectedLanguage {
Picture(systemName: "checkmark")
.foregroundColor(.major)
}
}
.onTapGesture {
selectedLanguage = lang
}
}
}
}
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button("Save") {
appSetting.language = selectedLanguage
dismiss()
}
}
ToolbarItem(placement: .topBarLeading) {
Button("Cancel") {
dismiss()
}
}
}
.navigationTitle("Settings")
.navigationBarTitleDisplayMode(.inline)
}
.onAppear {
selectedLanguage = appSetting.language
}
}
}
#Preview {
SettingView()
.environmentObject(AppSetting())
}
The view merely lists the out there languages as outlined in AppLanguage
. The presently chosen language exhibits a checkmark subsequent to it. When the person faucets “Save,” the chosen language is saved to the shared AppSetting
 object, and the view is dismissed.
In the principle view, we add a Setting button and use the .sheet
modifier to show the Setting view.
struct ContentView: View {
@EnvironmentObject var appSetting: AppSetting
@State non-public var showSetting: Bool = false
var physique: some View {
VStack {
HStack {
Spacer()
Button {
showSetting.toggle()
} label: {
Picture(systemName: "gear")
.font(.system(measurement: 30))
.tint(.major)
}
}
Textual content("ProLingo")
.font(.system(measurement: 75, weight: .black, design: .rounded))
Textual content("Be taught programming languages by engaged on actual initiatives")
.font(.headline)
.padding(.horizontal)
.
.
.
.
.
.
}
.padding()
.sheet(isPresented: $showSetting) {
SettingView()
.environmentObject(appSetting)
}
}
}
Enabling Actual-Time Language Adjustments
At this level, tapping the gear button will convey up the Settings view. Nevertheless, the app would not replace its language when the person selects their most well-liked language. To implement dynamic language switching, we have now to connect the .setting
modifier to ContentView
and replace the locale to match the person’s choice like this:
VStack {
...
}
.setting(.locale, Locale(identifier: appSetting.language.id))
This line of code injects a customized Locale
into the SwiftUI setting. The .locale
key controls which language and area SwiftUI makes use of for localizable views like Textual content
. The locale is ready to match the language the person chosen in settings.
The app can now replace its language on the fly. For instance, open the Settings view and choose Conventional Chinese language. After saving your choice and returning to the principle view, you may see the UI immediately up to date to show all textual content in Conventional Chinese language.

Utilizing LocalizedStringKey
It’s possible you’ll discover a bug within the app. After altering the language to Conventional Chinese language (or different languages) and reopening the Settings view, the language names nonetheless show in English.

Let’s check out the code that handles the show of language identify:
Textual content(lang.displayName)
It’s possible you’ll surprise why the Textual content
view doesn’t deal with the localization robotically. On this case, SwiftUI treats lang.displayName
as a plain textual content, which suggests no computerized localization occurs, even when the string matches a key within the String Catalog file. To make the localization work, you might want to convert the String
to a LocalizedStringKey
like this:
Textual content(LocalizedStringKey(lang.displayName))
Utilizing LocalizedStringKey
triggers the localization lookup course of. Whenever you run the app once more, you may see the language names within the Settings view displayed in your chosen language.

Abstract
On this tutorial, you discovered easy methods to implement in-app language switching in iOS utilizing SwiftUI, permitting customers to alter languages with out restarting the app. We explored easy methods to create a Settings display for language choice, enabled real-time localization updates, and discovered the significance of utilizing LocalizedStringKey
for correct string localization.
The code and ideas introduced right here present a basis for implementing language switching in your personal iOS apps. Be at liberty to adapt this strategy on your personal iOS apps that require multi-language assist.