201

I want get the language code of the device (en, es...) in my app written with Swift. How can get this?

I'm trying this:

var preferredLanguages : NSLocale!
let pre = preferredLanguages.displayNameForKey(NSLocaleIdentifier, value: preferredLanguages)

But this returns nil.

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
user3739367
  • 4,161
  • 6
  • 20
  • 18

18 Answers18

244

In Swift 3

let langStr = Locale.current.languageCode
Miki
  • 40,887
  • 13
  • 123
  • 202
Vadim Motorine
  • 2,973
  • 1
  • 11
  • 7
  • 22
    should be : Locale.current.identifier but Locale.current.languageCode for Chinese, it always return 'zh' , but it have to be distinguish zh-HK, etc – iXcoder Jun 17 '17 at 11:23
  • 3
    @User9527 Because of you most likely didn't enable localization for that language in your project settings. – Kirill Mar 11 '19 at 23:56
  • 1
    Cannot assign value of type 'String' to type 'Locale?' – Puji Wahono Jul 04 '19 at 07:40
  • 10
    As far as I notice, it will return actual language set in Settings -> General -> Language & Region -> iPhone Language ONLY IF localization for this language enabled in your project under Project -> Localizations. Otherwise it's development language. – Huralnyk Nov 19 '19 at 15:30
  • How I make an executable binary that outputs this value, using only the commandline version of xcode? – HappyFace Oct 18 '20 at 18:11
137

It's important to make the difference between the App language and the device locale language (The code below is in Swift 3)

Will return the Device language:

let locale = NSLocale.current.languageCode

Will return the App language:

let pre = Locale.preferredLanguages[0]
Alexander Pacha
  • 9,187
  • 3
  • 68
  • 108
raed
  • 4,887
  • 4
  • 30
  • 49
  • 9
    I don't understand the difference between Device Language or App Language. Do you have any documentation about the difference? – Jeremiah Apr 12 '18 at 22:45
  • 3
    @Jeremiah locale will contain the device language, for example your device language is configured to French. Pre will contain the user (Or App) preferred language, example: your App support only Chinese, so you can install a Chinese app on a French device. Hope I clarified this 4 u – raed Apr 22 '18 at 17:26
  • When you say the device is configured to french what do you mean? It seems that if I change the language in settings to something other than english it is represented in preferredLanguages but not in languageCode. How is languageCode changed? – Jeremiah Apr 23 '18 at 22:38
  • If you change the in settings to something other that English you will get its value in NSLocale.current.languageCode – raed Apr 24 '18 at 09:24
  • 22
    Isn't it the other way around? When my app development language is EN and I run on a DE configured device, for which I have localized the app the result is: `Locale.current.languageCode: de Locale.current.identifier: de_DE Locale.preferredLanguages[0]: de` When my app development language is EN and I run on a FR configured device, for which I have *not* localized the app the result is: `Locale.current.languageCode: en Locale.current.identifier: en_FR Locale.preferredLanguages[0]: fr` – Arjen Hiemstra Nov 12 '18 at 13:08
  • @ArjenHiemstra what I see here is that you're getting always the device language in preferredLanguages[0], probably you're not seeing your development language correctly! To force the App language you should do it via the Scheme, please check the url https://medium.com/lean-localization/ios-localization-tutorial-938231f9f881 – raed Nov 12 '18 at 14:09
  • @ArjenHiemstra If you need more help we need to do it other way that here! Think of something. – raed Nov 12 '18 at 14:09
  • I did set up schemes to test the above. 1 scheme witGerman/Germany and 1 scheme with French/France. The locale the app operates in is DE if I have a DE localization and EN (my development language) if I do not have the localization for the device. At least that is what I am seeing? – Arjen Hiemstra Nov 19 '18 at 11:33
  • @ArjenHiemstra can you give me access to your code? A github link! – raed Nov 25 '18 at 11:33
  • @raed Did you reproduce? – Arjen Hiemstra Nov 29 '18 at 20:19
  • @ArjenHiemstra Sorry for being late, it's weird, but I m always getting DE for all parameters even if my device is EN or FR! – raed Nov 30 '18 at 08:54
  • 3
    This is wrong for 1 more reason: iOS 13.1 introduces per-app language setting, and `Locale.preferredLanguages[0]` doesn't take that into account, whereas `Locale.current.languageCode` does. – Oleksii Nezhyborets Oct 03 '19 at 15:29
  • I tried to find out how "iOS 13.1 per-app language setting" is done, and can't get it? My app supports 12 languages and is set by the device language settings. Looks like I should scan the list Locale.preferredLanguages from the top and see if I get any hit, if not English. But shall I declare the languages (capabilities) in the code of the app? – Jan Bergström Oct 31 '19 at 05:50
  • For me, inside the debugging console (lldb). Both Locale.preferredLanguages[0] and NSLocale.current.languageCode display the same answer "en", but my iPhone is not set to English. Do you have an explanation for that? – Michel Nov 13 '19 at 15:19
  • I think this is no longer working in new iOS versions! @Michel – raed Nov 14 '19 at 09:14
  • This is the wrong way around... `Locale.current.languageCode` is the current app language – Nick McConnell Feb 07 '23 at 00:09
72

Swift 4 & 5:

Locale.current.languageCode
Bogdan Bystritskiy
  • 1,325
  • 12
  • 10
46

Swift 3 & 4 & 4.2 & 5

Locale.current.languageCode does not compile regularly. Because you did not implemented localization for your project.

You have two possible solutions

1) String(Locale.preferredLanguages[0].prefix(2)) It returns phone lang properly.

If you want to get the type en-En, you can use Locale.preferredLanguages[0]

2) Select Project(MyApp)->Project (not Target)-> press + button into Localizations, then add language which you want.

kuzdu
  • 7,124
  • 1
  • 51
  • 69
Ali Ihsan URAL
  • 1,894
  • 1
  • 20
  • 43
  • This is really interesting! Where did you read solution one? Cannot find this information in the apple documentation – kuzdu May 21 '19 at 13:08
  • This solution is right. I had tried much with other codes but it was due to 2) reason. – Guru Dev Nov 06 '21 at 16:44
46

TL;DR:

Use Bundle.main.preferredLocalizations[0] to get the language your app's UI is currently displayed in. Don't use Locale.current because it describes the region format (time, currency, distance, etc) and has nothing to do with language.

Detailed Answer:

The definite answer about how to get the language(!) code for the language your app's UI is displayed in comes from Apple engineer Quinn "The Eskimo", and I quote/paraphrase for Swift:

Locale.current returns the current locale, that is, the value set by Settings > General > Language & Region > Region Formats. It has nothing to do with the language that your app is running in. It's perfectly reasonable, and in fact quite common, for users in the field to have their locale and language set to 'conflicting' values. For example, a native English speaker living in France would have the language set to English but might choose to set the locale to French (so they get metric weights and measures, 24 time, and so on).

The language that your app runs in is determined by the language setting, that is, Settings > General > Language & Region > Preferred Language Order. When the system runs your app it takes this list of languages (the preferred list) and matches it against the list of languages that your app is localised into (the app list). The first language in the preferred list that exists in the app list is the language chosen for the app. This is what you'll find in the first entry of the main bundle's preferredLocalizations array.

Language Name from Code

To get the human-readable name of a language from its code, you can use this:

let langCode = Bundle.main.preferredLocalizations[0]
let usLocale = Locale(identifier: "en-US")
var langName = ""
if let languageName = usLocale.localizedString(forLanguageCode: langCode) {
    langName = languageName
}
        

This will give you the English name of the current UI language.

Johannes Fahrenkrug
  • 42,912
  • 19
  • 126
  • 165
40

In Swift 3:

NSLocale.current.languageCode
mazorati
  • 2,031
  • 3
  • 22
  • 22
34

To get current language used in your app (different than preferred languages)

NSLocale.currentLocale().objectForKey(NSLocaleLanguageCode)!
Undo
  • 25,519
  • 37
  • 106
  • 129
Benknopf
  • 422
  • 4
  • 5
22

swift 3

let preferredLanguage = Locale.preferredLanguages[0] as String
print (preferredLanguage) //en-US

let arr = preferredLanguage.components(separatedBy: "-")
let deviceLanguage = arr.first
print (deviceLanguage) //en
Jordan Montel
  • 8,227
  • 2
  • 35
  • 40
Bassant Ashraf
  • 1,531
  • 2
  • 16
  • 23
  • 2
    Separate language code and country code by "-" is buggy. Your code will break on some cases like 'zh-Hans-US'. – kakaiikaka Oct 29 '19 at 07:05
  • `let langStr = Locale.preferredLanguages.first!`this is what I have done reviewing this post. It's working, and I compare with my languages with `langStr.lowercased().contains("es")` for all spanish language variations for example. – Ian Ortega Jan 09 '20 at 23:05
12

Locale.current.languageCode returns me wrong code, so I use these extensions:

extension Locale {
    static var preferredLanguageCode: String {
        guard let preferredLanguage = preferredLanguages.first,
              let code = Locale(identifier: preferredLanguage).languageCode else {
            return "en"
        }
        return code
    }
    
    static var preferredLanguageCodes: [String] {
        return Locale.preferredLanguages.compactMap({Locale(identifier: $0).languageCode})
    }
}
Peter Lapisu
  • 19,915
  • 16
  • 123
  • 179
ChikabuZ
  • 10,031
  • 5
  • 63
  • 86
11

Swift 5.4:

let languagePrefix = Locale.preferredLanguages[0]
print(languagePrefix)
Makwan Barzan
  • 353
  • 1
  • 6
  • 12
10

you may use the below code it works fine with swift 3

var preferredLanguage : String = Bundle.main.preferredLocalizations.first!
Amr Angry
  • 3,711
  • 1
  • 45
  • 37
6

I want to track the language chosen by the user in Settings app every time the user launches my app - that is not yet localized (my app is in English only). I adopted this logic:

  1. create an enum to to make it easier to handle the languages in array

    enum Language: String {
    
    case none = ""
    case en = "English"
    case fr = "French"
    case it = "Italian"
    
    } // add as many languages you want
    
  2. create a couple of extension to Locale

    extension Locale {
    
        static var enLocale: Locale {
    
            return Locale(identifier: "en-EN")
        } // to use in **currentLanguage** to get the localizedString in English
    
        static var currentLanguage: Language? {
    
            guard let code = preferredLanguages.first?.components(separatedBy: "-").last else {
    
                print("could not detect language code")
    
                return nil
            }
    
            guard let rawValue = enLocale.localizedString(forLanguageCode: code) else {
    
                print("could not localize language code")
    
                return nil
            }
    
            guard let language = Language(rawValue: rawValue) else {
    
                print("could not init language from raw value")
    
                return nil
            }
            print("language: \(code)-\(rawValue)")
    
            return language
        }
    }
    
  3. When you need, you can simply use the extension

    if let currentLanguage = Locale.currentLanguage {
        print(currentLanguage.rawValue)
        // Your code here.
    }
    
Miniapps
  • 292
  • 3
  • 3
  • Love the extension :). Wouldnt it makes more sense returning none if it's not able to read somehow. because that way that value can be used to make some value. – Alok C Aug 15 '18 at 14:20
6

In Swift, You can get the locale using.

let locale = Locale.current.identifier
yo2bh
  • 1,356
  • 1
  • 14
  • 26
5

This is what I use in Swift 5 Xcode 11:

Inside the class variables:

let languagePrefix = Bundle.main.preferredLocalizations.first?.prefix(2)

This comes as a string. It returns 2 characters, i.e. "en", "es", "de"...

From this I can easily determine what language to display:

 if languagePrefix == "es" { self.flipCard.setTitle("última carta", for: .normal) }
 if languagePrefix == "en" { self.flipCard.setTitle("Last Card", for: .normal) }

If you want the full information of the language, then remove ?.prefex(2)

Brian M
  • 331
  • 3
  • 10
2

in most cases you want to get the language code of the current app UI, to send over an API to get localized response

extension Bundle {
    
    var currentLocalizedUILanguageCode: String {
        guard let code = Bundle.main.preferredLocalizations.first?.components(separatedBy: "-").first else {
            return Locale.current.languageCode ?? "en"
        }
        return code
    }
    
}

use like

headers["X-Language"] = Bundle.main.currentLocalizedUILanguageCode
Peter Lapisu
  • 19,915
  • 16
  • 123
  • 179
0
var languageCode = ""
 if #available(iOS 16.0, *) {
   if let language = NSLocale.current.language.languageCode {
     languageCode = language.identifier
   }
 } else {
   if let language = NSLocale.current.languageCode {
     languageCode = language
   }
 }
-1

use this function for get your system's current language code from iOS devices

    func getSystemLanguageCode() -> String {
    UserDefaults.standard.removeObject(forKey: "AppleLanguages")
    let pref_Language = NSLocale.preferredLanguages[0] as String //"fr-IN"
    let language = pref_Language.components(separatedBy: "-") //["fr","IN"]
    let lang_Code = language.first?.lowercased() ?? "" //"fr"
    UserDefaults.standard.set([lang_Code], forKey: "AppleLanguages")
    
    return lang_Code
}
-1

Almost none of the answers are correct. This is a working Swift 5.7 solution. ""

extension Locale {
    // Gets the language of the device, had to remove the content of AppleLanguages since `preferredLanguages`
    // is combining the result from multiple APIs. AppleLanguage is then set to the old value
    static var preferredLanguageCode: String {
        let appleLanguages = UserDefaults.standard.stringArray(forKey: "AppleLanguages")
        UserDefaults.standard.removeObject(forKey: "AppleLanguages")

        guard let preferredLanguage = preferredLanguages.first,
              let code = Locale(identifier: preferredLanguage).languageCode else {
            UserDefaults.standard.set(appleLanguages, forKey: "AppleLanguages")
            return "en"
        }
        UserDefaults.standard.set(appleLanguages, forKey: "AppleLanguages")
        return code
    }
}
Boris Nikolic
  • 746
  • 14
  • 24