Getting the Current Language and Locale

If your application is properly internationalized, you should rarely have to choose which localization to apply to use. The routines associated with the NSBundle class and CFBundleRef opaque type automatically apply the user’s preferences to determine which localized resource files to return in response to a programmatic request. However, there may be situations beyond simply loading resources from a bundle that would require your program to know which localization was in use. For those situations, both NSBundle and CFBundleRef provides ways for you to get that information.

Specifying the Supported Localizations in Your Bundle

Before discussing the techniques of how to get localizations, it is important to remember how a bundle communicates its supported localizations to the system. The directory containing the bundle’s resources can also contain one or more language-specific project (.lproj) directories. Each of these .lproj directories contains the resources associated with a specific language or regional dialect. The methods of the NSBundle class and functions associated with the CFBundleRef opaque type look for these directories and use them to build a list of supported localizations. However, this is not the only way to build this list.

An application can notify the system that it supports additional localizations through its information property list (Info.plist) file. To specify localizations not included in your bundle’s .lproj directories, add the CFBundleLocalizations key to this file. The value for the key is an array of strings, each of which contains an ISO language designator as described in “Language and Locale Designations.”

Getting the Preferred Localizations

If you are using the functions associated with the CFBundleRef opaque type to manage your program bundle, you can use the CFBundleCopyPreferredLocalizationsFromArray function to get the most relevant localizations. When calling this method, you must pass in a list of localizations your software supports.

You can also use the function CFBundleCopyBundleLocalizations to generate this list for you using the bundle information. This function compares your application’s supported localizations against the user’s language and region preferences. The function then returns an array of strings with a handful of localizations. One of them is the language-only localization most appropriate for the user. If a region-specific localization is also available, the function returns it as well, giving it precedence over the language-only localization.

If you are writing your application in Objective-C, you can use the preferredLocalizationsFromArray: and localizations methods of the NSBundle class to implement the same behavior as the CFBundleCopyPreferredLocalizationsFromArray and CFBundleCopyBundleLocalizations functions. You can also use the preferredLocalizations method as a shortcut to perform both actions with a single method. As with the Core Foundation functions, the preferredLocalizations and preferredLocalizationsFromArray: methods return an array of strings containing the language designators in use by the bundle.

Getting Canonical Language and Locale IDs in OS X

Prior to OS X v10.4, language dialects were specified by combining a language designator with a region designator. With the introduction of support for custom dialect codes (see “Language and Locale IDs”), getting the appropriate language code is now somewhat more complicated. Fortunately, OS X provides routines to help you determine the appropriate language and locale codes based on the information you have.

In OS X v10.3, the CFLocaleRef opaque type was introduced in Core Foundation. One of the functions introduced with this type is the CFLocaleCreateCanonicalLocaleIdentifierFromString function, which takes the locale code you specify and returns an appropriate canonical version. This function is particularly useful for converting older locale strings, such as the older, English-based .lproj directory names, into the ISO-compliant names.

In OS X v10.4, the CFLocaleCreateCanonicalLanguageIdentifierFromString function was added to perform the same canonical conversion for language and dialect codes. For example, this function converts the old specifier for traditional Chinese (zh_TW) to the more modern version (zh-Hant). Also in OS X v10.4, Cocoa added the NSLocale class to provide Objective-C wrappers for the corresponding Core Foundation functions.

If you use a CFBundleRef type or NSBundle object to retrieve language-specific resources from your bundle, then you do not need to worry about language identifiers directly. The CFBundleRef and NSBundle routines automatically handle language and locale IDs in canonical and non-canonical forms.

If your code requires OS X v10.4 or later, you should start using the new canonical forms for language and locale IDs. Some older language codes are replaced by newer codes in v10.4. In addition to several of the Chinese language codes, support for the newer Norwegian ISO code (nb) is now available and should be preferred over the older version.

Getting Language and Locale Preferences Directly in OS X

There may be situations where you want to get the preferred locale ID or the list of languages directly from the user preferences. OS X stores each user’s list of preferred languages in that user’s defaults database. The list of preferred languages is identified by the defaults key AppleLanguages and is stored in the global variable NSGlobalDomain. You can access that list using the NSUserDefaults class in Cocoa or the Core Foundation preferences functions.

The following example shows you to get the list of preferred languages from the defaults database using Cocoa. The returned array contains the languages associated with the AppleLanguages key in the user's preferred order. Thus, in most cases, you would simply want to get the first object in the array.

NSUserDefaults* defs = [NSUserDefaults standardUserDefaults];
NSArray* languages = [defs objectForKey:@"AppleLanguages"];
NSString* preferredLang = [languages objectAtIndex:0];

The locale for the current user is also stored in the defaults database under the AppleLocale key.