iOS development
NSLocalizedString
language settings
app localization
programming tutorial

How to force NSLocalizedString to use a specific language

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

NSLocalizedString normally uses the system-preferred language order, which is correct for most apps but not always enough for in-app language switching. If you need to force a specific language, load strings from a chosen bundle instead of relying on default lookup. This keeps localization explicit and testable.

Why Default Lookup Is Not Enough

NSLocalizedString resolves keys using the main bundle and user language preferences. When product requirements include a language selector inside the app, default behavior can lag behind current selection until restart or may not affect all UI surfaces consistently.

A deterministic approach is to resolve the target .lproj bundle and fetch localized strings directly.

swift
1import Foundation
2
3final class Localizer {
4    static let shared = Localizer()
5    private var bundle: Bundle = .main
6
7    func setLanguage(_ code: String) {
8        guard let path = Bundle.main.path(forResource: code, ofType: "lproj"),
9              let langBundle = Bundle(path: path) else {
10            bundle = .main
11            return
12        }
13        bundle = langBundle
14    }
15
16    func text(_ key: String) -> String {
17        return NSLocalizedString(key, bundle: bundle, comment: "")
18    }
19}

This isolates localization behavior behind one interface.

Updating UI After Language Change

Changing bundle selection does not automatically refresh every visible view. You need a refresh mechanism, such as reloading root controllers or broadcasting a language-change event that screens observe.

swift
1import UIKit
2
3extension Notification.Name {
4    static let languageDidChange = Notification.Name("languageDidChange")
5}
6
7func applyLanguage(_ code: String) {
8    Localizer.shared.setLanguage(code)
9    NotificationCenter.default.post(name: .languageDidChange, object: nil)
10}

In each view controller, subscribe to this notification and update visible labels in one dedicated method.

Persisting User Choice Safely

Store language choice in user defaults and apply it during app startup before creating major UI flows. This avoids mixed-language screens and flicker.

swift
1let languageKey = "selectedLanguage"
2
3func saveLanguage(_ code: String) {
4    UserDefaults.standard.set(code, forKey: languageKey)
5}
6
7func loadLanguage() -> String {
8    return UserDefaults.standard.string(forKey: languageKey) ?? "en"
9}

Keep fallback language logic explicit. If translation files are missing, degrade gracefully to default strings and log missing keys for localization QA.

Testing Localization Behavior

Add automated checks that verify key screens in at least two languages. Also test runtime switching paths and right-to-left layouts where applicable. Localization bugs often hide in custom controls and formatted strings, so include date, number, and pluralization samples in test coverage.

Formatted Strings and Pluralization

After forcing bundle selection, also verify formatted and pluralized strings behave correctly. Plain key lookup is only part of localization quality. Date formatting, number formatting, and plural rules can still show mixed language output if they rely on default locale settings.

swift
1import Foundation
2
3func localizedCountMessage(count: Int, locale: Locale) -> String {
4    let format = Localizer.shared.text("item_count_format")
5    let number = NumberFormatter()
6    number.locale = locale
7    let rendered = number.string(from: NSNumber(value: count)) ?? "\(count)"
8    return String(format: format, rendered)
9}

Set locale-sensitive formatters explicitly when users pick an in-app language. Otherwise, translated labels may coexist with system-locale date or number styles and create inconsistent UX.

For multilingual QA, create a checklist that includes truncated labels, long translated strings, and right-to-left screenshots where applicable. Forced-language systems are only reliable when the entire UI, including alerts and error messages, follows the same language source and locale rules.

Common Pitfalls

  • Expecting plain NSLocalizedString calls to update existing UI automatically after language selection changes.
  • Storing selected language but applying it only after most UI has already rendered.
  • Hardcoding user-facing text in controllers and bypassing localization entirely.
  • Forgetting fallback behavior when requested .lproj bundle is missing.
  • Updating labels manually in many places instead of centralizing refresh logic.

Summary

  • Force specific language by reading localized strings from a chosen bundle.
  • Wrap localization in a small service to keep behavior consistent.
  • Broadcast language changes and refresh visible UI explicitly.
  • Persist user language choice and apply it early at startup.
  • Test runtime switching and fallback paths to avoid mixed-language output.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.