An important part of the localization process is to localize all of the text strings displayed by your application. By their nature, strings located in nib files can be readily localized along with the rest of the nib file contents. Strings embedded in your code, however, must be extracted, localized, and then reinserted back into your code. To make the maintenance of your code easier, Mac OS X ships with a tool that extracts strings from your code and puts them into resource files where they can be localized more easily. This article talks about the process for extracting strings from your code and managing the corresponding resources files.
About Strings Files
Creating Strings Resource Files
Loading String Resources Into Your Code
Advanced Strings File Tips
Resource files that contain localizable strings are referred to as strings files (with the deliberate extra 's' in the word "strings") because of their filename extension, which is .strings
. You can create strings files manually or programmatically depending on your needs. The standard strings file format consists of one or more key-value pairs along with optional comments. The key and value in a given pair are strings of text enclosed in double quotation marks, separated by an equal sign, and terminated by a semicolon. (You can also use a property list format for strings files. In such a case, the top-level node is a dictionary and each key-value pair of that dictionary is a string entry.) Although the inclusion of comments is optional, they do provide a useful way to communicate contextual information to the translator about how each string is used. Listing 1 shows a simple strings file with two non-localized entries for the default language.
Listing 1 A simple strings file
/* Insert Element menu item */ |
"Insert Element" = "Insert Element"; |
/* Error string used for unknown error types. */ |
"ErrorString_1" = "An unknown error occurred."; |
A typical application has at least one strings file per localization, that is, one strings file in each of the bundle’s .lproj
subdirectories. The name of the default strings file is Localizable.strings
but you can create strings files with any file name you choose. Creating strings files is discussed in more depth in “Creating Strings Resource Files.”
Note: It is recommended that you save strings files using the UTF-16 encoding, which is the default encoding for standard strings files. It is possible to create strings files using other property-list formats, including binary property-list formats and XML formats that use the UTF-8 encoding, but doing so is not recommended. For more information about the standard strings file format, see “Creating Strings Resource Files.” For more information about Unicode and its text encodings, go to http://www.unicode.org/ or http://en.wikipedia.org/wiki/Unicode.
Although you can create strings files manually, it is rarely necessary to do so. The easiest way to create strings files is to write your code using the appropriate string-loading macros and then use the genstrings
command-line tool to extract those strings and create strings files for you.
The following sections describe the process of how to set up your source files to facilitate the use of the genstrings
tool. For detailed information about the tool, see genstrings
man page.
When it comes to localizing your application’s interface, it is not always appropriate to localize every string used by your application. Translation is a costly process, and translating strings that are never seen by the user is a waste of time and money. Strings that are not displayed to the user, such as notification names used internally by your application, do not need to be translated. Consider the following example:
if (CFStringHasPrefix(value, CFSTR("-")) { CFArrayAppendValue(myArray, value);}; |
In this example, the string “-
” is used internally and is never seen by the user; therefore, it does not need to be placed in a strings file.
The following code shows another example of a string the user would not see. The string "%d %d %s"
does not need to be localized, since the user never sees it and it has no effect on anything that the user does see.
matches = sscanf(s, "%d %d %s", &first, &last, &other); |
Because nib files are localized separately, you do not need to include strings that are already located inside of a nib file. Some of the strings you should localize, however, include the following:
Strings that are programmatically added to a window, panel, view, or control and subsequently displayed to the user. This includes strings you pass into standard routines, such as those that display alert boxes.
Menu item title strings if those strings are added programmatically. For example, if you use custom strings for the Undo menu item, those strings should be in a strings file.
Error messages that are displayed to the user.
Any boilerplate text that is displayed to the user.
Some strings from your application’s information property list (Info.plist
) file; see Runtime Configuration Guidelines.
New file and document names.
The Foundation and Core Foundation frameworks define the following macros to make loading strings from a strings file easier:
Core Foundation macros:
CFCopyLocalizedString
CFCopyLocalizedStringFromTable
CFCopyLocalizedStringFromTableInBundle
CFCopyLocalizedStringWithDefaultValue
Foundation macros:
NSLocalizedString
NSLocalizedStringFromTable
NSLocalizedStringFromTableInBundle
NSLocalizedStringWithDefaultValue
You use these macros in your source code to load strings from one of your application’s strings files. The macros take the user’s current language preferences into account when retrieving the actual string value. In addition, the genstrings
tool searches for these macros and uses the information they contain to build the initial set of strings files for your application.
For detailed information about how to use these macros, see “Loading String Resources Into Your Code.”
At some point during your development, you need to create the strings files needed by your code. If you wrote your code using the Core Foundation and Foundation macros, the simplest way to create your strings files is using the genstrings
command-line tool. You can use this tool to generate a new set of strings files or update a set of existing files based on your source code.
To use the genstrings
tool, you typically provide at least two arguments:
A list of source files
An optional output directory
The genstrings
tool can parse C, Objective-C, and Java code files with the .c
, .m
, or .java
filename extensions. Although not strictly required, specifying an output directory is recommended and is where genstrings
places the resulting strings files. In most cases, you would want to specify the directory containing the project resources for your development language.
The following example shows a simple command for running the genstrings
tool. This command causes the tool to parse all Objective-C source files in the current directory and put the resulting strings files in the en.lproj
subdirectory, which must already exist.
genstrings -o en.lproj *.m |
The first time you run the genstrings
tool, it creates a set of new strings files for you. Subsequent runs replace the contents of those strings files with the current string entries found in your source code. For subsequent runs, it is a good idea to save a copy of your current strings files before running genstrings
. You can then diff the new and old versions to determine which strings were added to (or changed in) your project. You can then use this information to update any already localized versions of your strings files, rather than replacing those files and localizing them again.
Within a single strings file, each key must be unique. Fortunately, the genstrings
tool is smart enough to coalesce any duplicate entries it finds. When it discovers a key string used more than once in a single strings file, the tool merges the comments from the individual entries into one comment string and generates a warning. (You can suppress the duplicate entries warning with the -q
option.) If the same key string is assigned to strings in different strings files, no warning is generated.
For more information about using the genstrings
tool, see the genstrings
man page.
Although the genstrings
tool is the most convenient way to create strings files, you can also create them manually. To create a strings file manually, create a new file in TextEdit (or your preferred text-editing application) and save it using the Unicode UTF-16 encoding. (When saving files, TextEdit usually chooses an appropriate encoding by default. You can force the encoding of a plain text file by choosing Save As and selecting the appropriate encoding. If the file is not a plain text file, you must first convert it by choosing Format > Make Plain Text.) The contents of this file consists of a set of key-value pairs along with optional comments describing the purpose of each key-value pair. Key and value strings are separated by an equal sign, and the entire entry must be terminated with a semicolon character. By convention, comments are enclosed inside C-style comment delimiters (/*
and */
) and are placed immediately before the entry they describe.
Listing 2 shows the basic format of a strings file. The entries in this example come from the English version of the Localizable.strings
file from the TextEdit application. The left side of each equal sign represents the key, and the right side represents the value. A common convention when developing applications is to use a key name that equals the value in the language used to develop the application. Therefore, because TextEdit was developed using the English language, the English version of the Localizable.strings
file has keys and values that match.
Listing 2 Strings localized for English
/* Menu item to make the current document plain text */ |
"Make Plain Text" = "Make Plain Text"; |
/* Menu item to make the current document rich text */ |
"Make Rich Text" = "Make Rich Text"; |
Listing 3 shows the German translation of the same entries. These entries also live inside a file called Localizable.strings
, but this version of the file is located in the German language project directory of the TextEdit application. Notice that the keys are still in English, but the values assigned to those keys are in German. This is because the key strings are never seen by end users. They are used by the code to retrieve the corresponding value string, which in this case is in German.
Listing 3 Strings localized for German
/* Menu item to make the current document plain text */ |
"Make Plain Text" = "In reinen Text umwandeln"; |
/* Menu item to make the current document rich text */ |
"Make Rich Text" = "In formatierten Text umwandeln"; |
AppKit–based applications can take advantage of built-in support to detect strings that do not need to be localized and those that need to be localized but currently are not. You enable this support using arguments that you pass to your executable at launch time. If you are using Xcode, you set these arguments using the inspector for the corresponding executable. Open an inspector window for the desired executable (located in the Executables section of your project window) and select the Arguments tab. Add an entry for the new argument and include both the argument string and the desired value (separated by a space) in the entry. The available argument strings are as follows:
The NSShowNonLocalizableStrings
setting identifies strings that are not localizable. The strings are logged to the shell in upper case. This option occasionally generates some false positives but is still useful overall.
The NSShowNonLocalizedStrings
setting locates strings that were meant to be localized but could not be found in the application’s existing strings files. You can use this setting to catch problems with out-of-date localizations.
You can also pass arguments to an application by running that application from the command line. For example, to use the NSShowNonLocalizedStrings
setting with the TextEdit application, you would enter the following in Terminal:
/Applications/TextEdit.app/Contents/MacOS/TextEdit -NSShowNonLocalizedStrings YES |
The Core Foundation and Foundation frameworks provide macros for retrieving strings stored in strings files. Although the main purpose of these macros is to load strings at runtime, they also serve a secondary purpose by acting as markers that the genstrings
tool can use to locate your application’s string resources. It is this second purpose that explains why many of the macros let you specify much more information than would normally be required for loading a string. The genstrings
tool uses the information you provide to create or update your application’s strings files automatically. Table 1 lists the types of information you can specify for these routines and describes how that information is used by the genstrings
tool.
Parameter | Description |
---|---|
Key | The string used to look up the corresponding value. This string must not contain any characters from the extended ASCII character set, which includes accented versions of ASCII characters. If you want the initial value string to contain extended ASCII characters, use a routine that lets you specify a default value parameter. (For information about the extended ASCII character set, see the corresponding Wikipedia entry.) |
Table name | The name of the strings file in which the specified key is located. The |
Default value | The default value to associate with a given key. If no default value is specified, the |
Comment | Translation comments to include with the string. You can use comments to provide clues to the translation team about how a given string is used. The |
Bundle | An |
When you request a string from a strings file, the Core Foundation and Cocoa macros automatically use the available localizations in your application and the current user’s language preferences to return the most appropriate string for that user. The string-loading macros search the application bundle for a strings file with the localization closest to the user’s preferred language and return that string for your code to use. As long as your code is properly internationalized, you should not have to do anything else. For information about how an appropriate localization is chosen, see “Language Preferences.”
The Core Foundation framework defines a single function and several macros for loading localized strings from your application bundle. The CFBundleCopyLocalizedString
function provides the basic implementation for retrieving the strings. However, it is recommended that you use the following macros instead:
CFCopyLocalizedString
(key, comment)
CFCopyLocalizedStringFromTable
(key, tableName, comment)
CFCopyLocalizedStringFromTableInBundle
(key, tableName, bundle, comment)
CFCopyLocalizedStringWithDefaultValue
(key, tableName, bundle, value, comment)
There are several reasons to use the macros instead of the CFBundleCopyLocalizedString
function. First, the macros are easier to use for certain common cases. Second, the macros let you associate a comment string with the string entry. Third, the macros are recognized by the genstrings
tool but the CFBundleCopyLocalizedString
function is not.
For additional information on how to use these macros, see Working With Localized Strings in Bundle Programming Guide. For macro and function syntax, see CFBundle Reference.
The Foundation framework defines a single method and several macros for loading string resources. The localizedStringForKey:value:table:
method of the NSBundle
class loads the specified string resource from a strings file residing in the current bundle. Cocoa also defines the following macros for getting localized strings:
NSLocalizedString
(key, comment)
NSLocalizedStringFromTable
(key, tableName, comment)
NSLocalizedStringFromTableInBundle
(key, tableName, bundle, comment)
NSLocalizedStringWithDefaultValue
(key, tableName, bundle, value, comment)
As with Core Foundation, Apple recommends that you use the Cocoa convenience macros for loading strings. The main advantage to these macros is that they can be parsed by the genstrings
tool and used to create your application’s strings files. They are also simpler to use and let you associate translation comments with each entry.
For information about the syntax of the preceding macros, see Foundation Functions Reference. Additional methods for loading strings are also defined in NSBundle Class Reference.
The following examples demonstrate the basic techniques for using the Foundation and Core Foundation macros to retrieve strings. Each example assumes that the current bundle contains a strings file with the name Custom.strings
that has been translated into French. This translated file includes the following strings:
/* A comment */ |
"Yes" = "Oui"; |
"The same text in English" = "Le même texte en anglais"; |
Using the Foundation framework, you can get the value of the “Yes
” string using the NSLocalizedStringFromTable
macro, as shown in the following example:
NSString* theString; |
theString = NSLocalizedStringFromTable (@"Yes", @"Custom", @"A comment"); |
Using the Core Foundation framework, you could get the same string using the CFCopyLocalizedStringFromTable
macro, as shown in this example:
CFStringRef theString; |
theString = CFCopyLocalizedStringFromTable(CFSTR("Yes"), CFSTR("Custom"), "A comment"); |
In both examples, the code specifies the key to retrieve, which is the string “Yes”. They also specify the strings file (or table) in which to look for the key, which in this case is the Custom.strings
file. During string retrieval, the comment string is ignored.
The following sections provide some additional tips for working with strings files and string resources.
The genstrings
tool searches for the Core Foundation and Foundation string macros by default. It uses the information in these macros to create the string entries in your project’s strings files. You can also direct genstrings
to look for custom string-loading functions in your code and use those functions in addition to the standard macros. You might use custom functions to wrap the built-in string-loading routines and perform some extra processing or you might replace the default string handling behavior with your own custom model.
If you want to use genstrings
with your own custom functions, your functions must use the naming and formatting conventions used by the Foundation macros. The parameters for your functions must match the parameters for the corresponding macros exactly. When you invoke genstrings, you specify the -s
option followed by the name of the function that corresponds to the NSLocalizedString
macro. Your other function names should then build from this base name. For example, if you specified the function name MyStringFunction
, your other function names should be MyStringFunctionFromTable
, MyStringFunctionFromTableInBundle
, and MyStringFunctionWithDefaultValue
. The genstrings
tool looks for these functions and uses them to build the corresponding strings files.
For some strings, you may not want to (or be able to) encode the entire string in a string resource because portions of the string might change at runtime. For example, if a string contains the name of a user document, you need to be able to insert that document name into the string dynamically. When creating your string resources, you can use any of the formatting characters you would normally use for handling string replacement in the Foundation and Core Foundation frameworks. Listing 4 shows several string resources that use basic formatting characters:
Listing 4 Strings with formatting characters
"Windows must have at least %d columns and %d rows." = |
"Les fenêtres doivent être composés au minimum de %d colonnes et %d lignes."; |
"File %@ not found." = "Le fichier %@ n’existe pas."; |
To replace formatting characters with actual values, you use the stringWithFormat:
method of NSString
or the CFStringCreateWithFormat
function, using the string resource as the format string. Foundation and Core Foundation support most of the standard formatting characters used in printf
statements. In addition, you can use the %@
specifier shown in the preceding example to insert the descriptive text associated with arbitrary Objective-C objects. See Formatting String Objects in String Programming Guide for Cocoa for the complete list of specifiers.
One problem that often occurs during translation is that the translator may need to reorder parameters inside translated strings to account for differences in the source and target languages. If a string contains multiple arguments, the translator can insert special tags of the form n$
(where n specifies the position of the original argument) in between the formatting characters. These tags let the translator reorder the arguments that appear in the original string. The following example shows a string whose two arguments are reversed in the translated string:
/* Message in alert dialog when something fails */ |
"%@ Error! %@ failed!" = "%2$@ blah blah, %1$@ blah!"; |
Just as in C, some characters must be prefixed with a backslash before you can include them in the string. These characters include double quotation marks, the backslash character itself, and special control characters such as linefeed (\n
) and carriage returns (\r
).
"File \"%@\" cannot be opened" = " ... "; |
"Type \"OK\" when done" = " ... "; |
You can include arbitrary Unicode characters in a value string by specifying \\U
followed immediately by up to four hexadecimal digits. The four digits denote the entry for the desired Unicode character; for example, the space character is represented by hexadecimal 20 and thus would be \\U0020
when specified as a Unicode character. This option is useful if a string must include Unicode characters that for some reason cannot be typed. If you use this option, you must also pass the -u
option to genstrings
in order for the hexadecimal digits to be interpreted correctly in the resulting strings file. The genstrings
tool assumes your strings are low-ASCII by default and only interprets backslash sequences if the -u
option is specified.
Note: The genstrings
tool always generates strings files using the UTF-16 encoding. If you include Unicode characters in your strings and do not use genstrings
to create your strings files, be sure to save your strings files in the UTF-16 encoding.
If you run into problems during testing and find that the functions and macros for retrieving strings are always returning the same key (as opposed to the translated value), run the /usr/bin/plutil
tool on your strings file. A strings file is essentially a property-list file formatted in a special way. Running plutil
with the -lint
option can uncover hidden characters or other errors that are preventing strings from being retrieved correctly.
© 2003, 2009 Apple Inc. All Rights Reserved. (Last updated: 2009-01-06)