If an application will be used in more than one part of the world, its resources should be customized, or localized, for the language, country, or cultural region. Cocoa provides a group of conventions and services, known as an internationalization architecture , that are flexible enough to enable multiple localizations of character strings, icons, user interfaces, and even context help packaged into your application. The localized resources appropriate to the user's preferences are dynamically loaded as needed.

The aim of Cocoa's localization architecture is to enable multilingual applications to be created without generating any new Objective-C code for each supported locale. Even if you don't have an immediate need for multilingual support in your application, it is always a good idea to keep the localization abilities of a Cocoa application in mind, so you can enable it when the need arises. With proper design, your application's source code won't have to be touched if and when it does need to be localized—minimizing the risk of introducing problems by modifying the code.

In this chapter, we'll take a look at how Cocoa's localization system works, how it depends on the user's language preferences, and how to structure your application's nib files and use of strings to take advantage of it.

What just happened here? By changing the System Preferences, TextEdit uses Mac OS X's and Cocoa's internationalization system to display the correct interface for the locale we specified. Under the hood, the system is using localized interface components stored within separate files and directories within the application's bundle.

Localizing Resources

In Chapter 13, we took a look at how Cocoa applications are packaged into application bundles. These bundles can contain multiple sets of resources, each set contained in a directory with an .lproj extension and identified by a combination of language and locale. The ability for bundles to hold all of the localized resources for an application, combined the ability for with bundle resource look-up routines to be aware of a user's language preferences, is what enables one version of an application to support multiple languages.

To get a feel for how localized resources are stored inside an application bundle, take a look at the contents of the Clock application.

Use the Finder to locate the Clock application (/Applications/Clock).

Control-click on the Clock application icon, and select Show Package Contents from the pop-up menu.

Select View → List from the Finder menus, browse through the application as shown in Figure 14-3, and notice the files shown.

Figure 14-3. Localized resources in the Clock application bundle

As you can see, the same files, Clock2.niband InfoPlist.strings, exist in various subfolders of the Resources folder. These subfolders, which have a language name or country code and a .lprojextension, contain the language-support files for the project.

Mac OS X defines localizations using three different conventions. Each convention allows a different degree of specificity.

The locale abbreviations consist of a language abbreviation (see Table 14-1), followed by an underscore and a two letter code. These codes, some of which are shown in Table 14-2, conform to the ISO 3166 specification that can identify a regional variant of a language.

A common practice of developers is to use the traditional language name for those that exist, then to use the language abbreviation, and then—only when necessary—the regional variant abbreviation.

Localized Resource Search Algorithm

Cocoa's various resource-handling methods in the NSBundle class automatically return the filesystem location of the resource that best matches the user's language and regional preferences. These methods look for resources of the following types until a matching resource is found:

Global Resource

Files that are stored at the top level of the Resources directory in the bundle

User Region Specific Resource

Files that are stored in a regional directory (such as en_UK.lproj) under the Resources directory, as specified by the user's preferences

User Language Specific Resources

Files that are stored in a regional directory (such as English.lproj, da.lproj, or French.lproj), as specified by the user's preferences

Developer Region Specific Resource

Files that are in a regional directory (such as en_UK.lproj), as specified by the region in which the application was developed

Developer Language Specific Resource

Files that are in a language directory (such as English.lproj, da.lproj, or French.lproj), as specified by the region in which the application was developed

Note that global resources take precedence over localized resources. This allows a quick return of resources that never change between locales, without going through the rest of the search process. You shouldn't have a global version of a resource if you have localized versions, as the localized versions will always be masked by a global version.

Localizing Nib Files

Nib files are typically localized all at once. A person performing localization takes a nib file, translates all the user-visible strings, and makes any adjustments that are necessary, such as resizing controls so that the translated strings appear correctly.

To illustrate how to localize nib files, we will create an application interface that isn't hooked up to anything, but which contains various controls that we can localize. The following steps will guide you:

Figure 14-5. Looking at the single localization of the MainMenu.nib file

Bring up the Info panel (Project → Show Info, or [[Image:Learning Cocoa with Objective-C_I_3_tt526.png|]]-I).

Select Add Localized Variant from the Localization & Platforms pop-up menu. You will be prompted for a locale. Enter French, as shown in Figure 14-6.

Figure 14-6. Adding a French localization of the MainMenu.nib file

Close the Info window by clicking on the red close window button.

You should see two localizations of the MainMenu.nib file in Project Builder.

Double-click the French variant to open it in Interface Builder.

Modify the various strings in the interface to match Figure 14-7. To type in the ç character, type Option-e, then e again (without the Option key). Notice that you'll have to resize the window and move things around to accommodate the longer text fields.

Figure 14-7. Our interface in French

Save the nib file ([[Image:Learning Cocoa with Objective-C_I_3_tt529.png|]]-S), and return to Project Builder.

Build and run the application ([[Image:Learning Cocoa with Objective-C_I_3_tt530.png|]]-R) to verify that everything works.

Launch the System Preferences application in the Dock, and click on the International button to open its preferences panel.

Change your language preferences from English to Français by clicking on Français and dragging it to the top of the list in the Languages window.

Run the application again to see the French interface run.

Quit and return to the System Preferences; reset your preferred language to English by dragging it to the top of the list.

Localizing Strings

Not all strings used by a program are located in a nib file. Many strings, such as those that appear in dialog boxes, are usually encoded directly in source code. To localize these strings without requiring changes to the source, Cocoa provides a function to look up strings against a strings file directly from code. This function has the following signature:

NSLocalizedString(NSString *key, NSString *comment);

This function uses the localizedStringForKey:value:table: method of the NSBundle class to look up the strings out of the main application bundle. We will add a couple of .stringsfiles (and a bit of code that uses them) in our project to illustrate how this works.

Add a new file, named Localizable.strings,to the project in Project Builder (File → New File → Empty File). Save it to the ~/LearningCocoa/Localization/English.lprojfolder. Make sure that it is in the Resources group, as shown in Figure 14-8.

Figure 14-8. Adding a Localizable.strings file

Edit the new file to have the following text:

"Not Submitted" = "Not Submitted";"Accepted" = "Accepted";

Bring up the Info panel (Project → Show Info, or [[Image:Learning Cocoa with Objective-C_I_3_tt535.png|]]-I).

Select Add Localized Variant from the Localization & Platforms pop-up menu. You will be prompted for a localization. Enter French, and then close the Info window.

Click on the disclosure triangle next to the Localizable.strings file. Beneath that, you will see two files: English, which we created in steps 1 and 2; and French, which we created in the previous step.