---
title: "How do I change the app language programmatically in iOS?"
description: "Apple's supported way is the per-app language in Settings (iOS 13 and later), which your app can open with `UIApplication.openSettingsURLString`. Writing to the `AppleLanguages` default needs a relaunch, and loading a specific `.lproj` bundle at runtime means re-rendering the UI yourself."
category: ios
date: 2026-10-09
canonical: https://localizely.com/i18n-questions/ios/how-do-i-change-the-app-language-programmatically-in-ios/
---

# How do I change the app language programmatically in iOS?

The supported answer is not to set it in code. Since iOS 13 users can choose a language for each app in Settings, and iOS relaunches the app in that language. A language option inside your app should send the user there:

```swift
if let url = URL(string: UIApplication.openSettingsURLString) {
    await UIApplication.shared.open(url)
}
```

The language row appears on your app's Settings page when the app ships more than one localization and the user has more than one preferred language in Language & Region. Apple's WWDC24 session "Build multilingual-ready apps" adds that `UIPrefersShowingLanguageSettings` set to `YES` in `Info.plist` shows the row even for users with a single language. Apple's guidance from WWDC19 is explicit: do not set the application language manually in code, because the system handles language and font fallbacks. To read the language the app is actually running in, use `Bundle.main.preferredLocalizations.first`, not `Locale.preferredLanguages`.

Two workarounds exist when that is not enough.

The `AppleLanguages` user default is the list the system reads to decide the app language. Writing to it affects the next launch, not the running process:

```swift
UserDefaults.standard.set(["fr"], forKey: "AppleLanguages")
// takes effect after the app is relaunched
```

Apple documents this key only as a testing launch argument (`-AppleLanguages "(fr)"` in the scheme editor), so treat it as undocumented behavior that may change.

Switching without a restart means bypassing the system: load the strings of one `.lproj` folder and re-render your views yourself.

```swift
let path = Bundle.main.path(forResource: "fr", ofType: "lproj")!
let french = Bundle(path: path)!
let title = french.localizedString(forKey: "settings_title", value: nil, table: nil)
```

Everything that does not go through that bundle keeps the launch language: system alerts and share sheets, formatters, and `String(localized:)`, whose `locale` parameter only changes number formatting, not which translation is loaded.

In SwiftUI, `.environment(\.locale, Locale(identifier: "fr"))` on a root view makes `Text` and the other views that take a `LocalizedStringKey` resolve French strings in that view tree. It is the mechanism Apple documents for previewing localizations, and it works at runtime for the views below the modifier, with the same limits as the bundle approach for everything else.

Source: https://localizely.com/i18n-questions/ios/how-do-i-change-the-app-language-programmatically-in-ios/
