Support for Internationalization
Both OS X and iOS support internationalization and localized content in a variety of ways.
They allow the user to specify a set of preferred languages.
They provide a mechanism for storing multiple language-versions of resources within an application.
OS X allows additional languages to be added to an application, even at run time.
The notion of a preferred language set and the mechanisms of bundles, localized resources, and runtime binding are behind this support.
How Users Specify Language Preferences
Users specify the languages they would prefer to see using the preferences of the target platform. Figure 1 shows the interface used to select language preferences in both OS X (v10.6) and iOS.
In iOS, the user designates a preferred language by navigating to General > International > Language in the Settings application. Because iOS-based devices support only one user, only one language at a time is selected. In OS X, the Language & Text system preference panel lets the user designate both a preferred language and one or more fallback languages in case the preferred language is unavailable.
The system stores the list of languages as a per-user default under the
AppleLanguages key. It is not recommended that you retrieve the value of this key directly though. The codes found in the database may not include the canonical forms of the language or locale IDs. Instead, you can use the
preferredLanguages method of the
NSLocale class or the
CFLocaleCopyPreferredLanguages function to retrieve the user’s list of preferred languages.
When your application requests the path to a resource file in its bundle directory, the bundle interfaces search for a resource whose localization most closely matches the preferred languages of the user. The bundle interfaces consist of the
NSBundle class in the Foundation framework and the functions supporting the
CFBundleRef type in Core Foundation. These interfaces provide support for locating resource files inside your application’s bundle directory. When searching that directory, they always return the localized resource that is most appropriate for the current user. If a localization does not exist for the user’s preferred language, the search continues using the user’s preferred fallback languages (where appropriate). If none of the bundle’s localizations match the user preferences, the interfaces return the resource associated with the localization used during development of the software.
When searching for resources in OS X, the bundle interfaces take into account the user’s preferred region settings in addition to the preferred language settings. For languages that have multiple dialects, an application can specify custom resource files for each region. For example, for the English language, an application might include different sets of resource files for users in the United States, Great Britain, Canada, and Australia. By using the user’s preferred region settings, the bundle interfaces are able to return even more precisely localized content to the user. This support is available in OS X only, though; in iOS, only the preferred language is taken into consideration.
How Users Specify Locale Preferences
Locale preferences convey regional differences for the way dates, times, and numbers are displayed. OS X and iOS specify predefined locales for many world regions, as shown in Figure 2. In iOS, the user can select the desired region only, but in OS X the user can also customize the information for any of the default locales to further personalize the system.
In most cases, your code should never have to worry about applying locale preferences. Most APIs take the user’s preferences into account when getting or formatting locale-sensitive data. However, there may still be situations where you need to get locale information. For example, you might want to display the current locale settings, do comparisons of different locales, or apply locales other than the current locale to a specific piece of data. In those situations, the Foundation framework provides the
NSLocale class and the Core Foundation framework provides the
CFLocaleRef opaque type for retrieving locale information.
An application bundle is a directory containing your application’s executable binary and any associated resource files. Although iOS supports only application bundles, OS X supports many different kinds of bundles, including framework and plug-in bundles. Bundles provide a way to organize complex pieces of software to make them more manageable. The bundle directory acts as a top-level container for all of the files needed to make the application run. The structure inside that directory is then used to separate code and resources and to organize them in ways that make it easier to find things.
In order to understand how resource files for multiple languages may be stored inside a single application bundle, it is worth taking the time to examine the basic bundle structure of an application. Listing 1 shows the partial structure of a Mac app that contains a few localized resource files. The text on the left identifies the directories and files in the bundle while the descriptions on the right indicate the purpose of the key items.
Listing 1 Structure of a Mac app bundle
MyApp.app/ The bundle directory
MyApp The application executable
Resources/ All resources go here
MyApp.icns Non-localized resources
en.lproj/ Resources localized for English
StopSign.eps A localized image
Localizable.strings Contains localized strings
MyApp.nib A localized nib file
fr.lproj/ Resources localized for French
ja.lproj/ Resources localized for Japanese
As you can see from this structure, an internationalized application needs one
.lproj directory for each localization it supports. The directories are named according to the language-version of the resources they contain. By default, a project directory contains only a single language directory corresponding to the language you are using to develop the application.
Although you could simply copy the files in your development language directory and translate them, the preferred way to create new localized resource files is using Xcode. When you select a resource file and open an inspector window, the General tab includes a Make Localizable button. Clicking this button for a resource file tells Xcode that it should place a copy of the original resource file in a language-specific project directory at build time. Each copy is based on the initial contents of the resource file. As your translators localize the files though, you can replace the initial file with the newly translated version and rebuild your project.
In an application bundle, there are several standard types of resources that require localization:
Nib files - Nib files are created by the Interface Builder application and comprise an encoded set of objects, including the configuration of those objects and the connections between them. A nib file can also include references to other resource files in your project, including image and sound resources.
Translation teams usually localize nib files directly using Interface Builder. A localizer takes a nib file (or, more typically, your application’s set of nib files), translates all the strings, and makes other adjustments as necessary. For example, if the new strings do not fit correctly, the translator may need to resize user interface objects to accommodate the new strings. Translators may also need to replace culture-specific images and sounds.
It is a good idea to minimize the number of objects stored in a single nib file. A common scenario is to include a single window (and any objects needed to support that window) in a nib file and place different windows in different nib files. Organizing your nib files in this manner typically improves the performance of your application and also allows localization to proceed incrementally.
Localized text strings - String resources are stored in a special type of file known as a strings file. A strings file is a text file with a
.stringsfilename extension. Any string resources that might be displayed to the user should be placed in strings files. For more information, see “Localizing String Resources.”
If your application displays resource file names to the user (such as image file or sound file names), you should store the resource file names themselves in a
.stringsfile. This way, you can translate the name of the resource file and its contents. To load the resource, you first request the resource file name from the corresponding
.stringsfile. Once you have the name, you can load the resource as usual.
Sounds - Like images, sound resources can be stored in any number of formats and opened using Core Audio or other audio technologies.
Online help - Online help files are typically stored as HTML files. The application’s property list allows you to specify which file your application should open when the user chooses the Help command. A localized variant of your help should be placed in the appropriate
.lprojdirectory for each targeted localization.
At localization time, you send the source-language
.lproj folder (for example,
en.lproj for developers in English-speaking countries) to a localization service, or to your in-house translation department. You also need to send the compiled application to allow the localizer to view dynamically-loaded resources in context, to ensure appropriate translations and to ensure adequate dimensions for user interface elements that display dynamically-loaded resources. For each target language, the translator sends back a
.lproj folder in which each resource file has been appropriately localized.
The tool used by localization teams to edit resource files varies by resource type. Nib files are typically edited using the Interface Builder application. Other resource files can be edited with an appropriate editor. For strings files, you can use most text editors in OS X. Whenever possible though, use an editor that can save text in Unicode format, such as the TextEdit application. String files saved in Unicode format can be used in a running application directly, while other file formats must be converted to Unicode before they can be used.
For more information about bundles, the structure of bundles (including the structure of iPhone applications), and how you use the bundle interfaces to locate resources, see Bundle Programming Guide.