When you installed Xcode, it installed a host of command-line tools. Included was the genstrings tool. genstrings scans code (C, Objective-C, C++, and others),
finds the string constants in NSLocalizedString ... macros, andcompiles them into .strings (with an ‘s’) files. Using the genstrings tool is one of the few times you need to step outside the comfortable confines of Xcode.
Launch the Terminal application from the Finder, the Dock, LaunchPad, or your favorite app-launching utility. Terminal lets you use OS X’s command shell. You’re going to run the genstrings tool
from the command line to scan all of the Objective-C source files in your project, compiling all
NSLocalizedString ... statements into a .strings file. Follow these steps:
1. Select the Pigeon folder group (not the project) in the project navigator.
2. Show the file inspector (on the right in Figure 22-9)
and click the arrow to the right of its Full Path. This will reveal the folder in the Finder.
Figure 22-9. Setting up the genstrings tool
3. Open a Terminal window and type cd, and the space bar (at the bottom in Figure 22-9). ‘cd’ is the shell’s change directory command.
4. In the Finder, drag the Pigeon folder, inside the Pigeon project folder, into the Terminal window and drop it.
5. Make sure the Terminal window is active again and press the Return key.
This sets the shell’s default directory to the Pigeon folder, which contains all of your source files and the es.lproj language bundle.
6. Type the command genstrings -o es.lproj *.m into the
Terminal window and press the Return key.
When genstrings is finished scanning all of your source files and creating a .strings file—which should happen faster than you can blink—a new Localizable.strings file will appear in the es.lproj bundle, as shown in Figure 22-10
This file isn’t a part of your project yet, so drag it into the Supporting Files group in the project navigator, also shown in Figure 22-10.
Figure 22-10. Adding the initial Localizable.strings file
Make sure the Pigeon target is selected and add it to the project.
Select the Localizable.strings file in the navigator and show the file inspector
(View ➤ Utilities ➤ Show File Inspector), as shown in Figure 22-11.
Figure 22-11. Newly created Localizable.strings file
A .strings file is a resource file containing a list of string substitutions. The format is reminiscent of C source. On the left of each = statement is the original string (the key). On the right is its localized translation (the value).Above each replacement is the comment, as a C-style comment, from the original NSLocalizedString ... statement.
Localizing Your Strings File
Select the Localizable.strings file. In the file inspector, find the Localization section. The Spanish localization, as shown in Figure 22-11, is the only language checked because there’s only one version of Localizable.strings. In thisproject, you only need a Localizable.strings file for Spanish. All other languages will use the original, untranslated, strings in the source code. When you’re ready to add a third language, simply check it in the Localization section ofthe file inspector and Xcode will duplicate the existing Localizable.strings file and copyit into the new language bundle. Then you’ll have a group of Localizable.strings file, just like Main_iPhone.storyboard. With the Localizable.strings file selected, edit the right (value) side of each string using Table 22-2.
Table 22-2. Spanish string constants
Comment Spanish String
Pin alert cancel button Cancelar Pin alert save button Recordar
Pin alert title ¿Lo que aquí?
Pin alert message Crear una letrero para esta ubicación.
Default location label ¡Aquí está!
When you’re finished, the edited .strings file should look something like the one in Figure 22-11.
Testing Your String Localization
Run Pigeon again. Assuming the user’s language setting is still set to Español, the app will appear in Spanish, as shown in Figure 22-12.
Figure 22-12. Spanish version of Pigeon
Here’s how it works. The NSLocalizedString... macros expand into code that sends a -localized StringForKey:value:table: message to the app’s NSBundle object, passing the literal string as the key. This method searches for a.strings file in the preferred localization bundle. If it finds a file, it searches that file for
the key (original string) and returns its translation.
The default .strings file is Localizable.strings, but you can define others if you have a lot of strings to organize.
Each strings file is referred to as a table, and you pass the name of the table in the -localizedStringForKey:value:table:message or NSLocalizedStringFromTable macro. Using those macros, genstrings will automatically create multiple .strings files, one for each table name. If there is no .strings file for that language,
or the key can’t be found in the .strings file, no translation is performed and the macro or message returns the
original string.
Localizing Interfaces Using Localizable Strings
Now that you understand .strings files, you can appreciate the use of .strings file to localize an Interface Builder file. When you localized Main_iPhone.storyboard, you localized the entire file by choosing the Interface BuilderCocoa Touch Storyboard option. You then proceeded to create a localized version of that storyboard.
If you had chosen the Localizable Strings option instead, Xcode would have created a localized strings file for that Interface Builder file, named Main_iPhone.strings. The file would have contained substitutions for various text properties (mostlycontrol titles) of the view objects in that interface, like this one:
"jkj-WQ-xYm.title" = "Remember Location";
The key is an identifier that only Interface Builder and iOS understand; don’t change it. In this instance, it identifiers the bar button item’s title property. Edit the value for your localization, like this:
"jkj-WQ-xYm.title" = "Recordar Ubicación";
When iOS loads the interface file, it replaces the appropriate text properties with those in the
Main_iPhone.strings file found in the localization bundle.
If the localized version of your interface can be accomplished by only altering the titles of control
and text objects, then use a localizable strings file rather than duplicating the entire Interface Builder file. The advantage is that you can later alter the Interface Builder file, adding new views, adjusting constrains, and so on,without having to replicate those changes in all of the copies you’ve made for other languages.
Those are the highlights of internationalization and localization. In the next couple of sections, I’m going to describe some unusual localization problems and tips on writing code to keep your app international.
Localizing Settings.bundle
One of Pigeon’s resources is the Settings.bundle that defines its settings in the Settings app. It’s a bundle, like your app’s bundle, and has its own localization bundles. If you expand it in the project navigator or Finder, you’llsee that it contains a Root.strings file in its default localization bundle. Select the Root.strings file, as shown in Figure 22-13.
Figure 22-13. Default Root.strings file
This file is left over from the original Settings.bundle template. It’s supposed to contain the translations for any visible strings in the Root.plist file. You edited the Root.plist file in Chapter 18, but never edited this file. Let’s fix
that now. Edit the English Root.strings file so it contains this:
"iCloud" = "iCloud";
"Sync Locations" = "Sync Locations";
The keys are the visible text—the group name and toggle switch title—in the settings bundle. Save the file (File ➤ Save). Unfortunately, the current version of Xcode doesn’t manage localized files inside other bundles, so you’llhave to create the Spanish localization manually. It’s pretty easy:
1. Open a Terminal window.
2. Type cd and the spacebar.
3. Drag the Settings.bundle directly from the project navigator in Xcode and drop it into the Terminal window.
4. Switch to the Terminal window and press Return.
5. Type the command cp -R en.lproj es.lproj and press Return, as shown in Figure 22-14.
Figure 22-14. Creating an es.lproj from the en.lproj bundle in Settings.bundle
Returning to Xcode, you’ll now see that the Settings.bundle contains a new es.lproj bundle, as shown in Figure 22-15.
Figure 22-15. Localized Settings.bundle strings
Expand the new es.lproj folder in the navigator, select the Root.strings file, and edit it as follows
(new text in bold):
"Sync Locations" = "Actualizar Ubicaciónes";
Run Pigeon. After it starts, press the home button and tap the Settings app—oops, I mean the Ajustes app. Find the settings for Pigeon and you’ll see its localized settings,
as shown in Figure 22-16.
Figure 22-16. Localized Pigeon settings
Other Code Considerations
In addition to language differences, there are also regional preferences that your app should be sensitive to. Most of these are handled automatically by iOS, as long as you let it. When writing your code, pay attention to theseissues:
n Visible messages
n Dates
n Numbers, including percentages and currency
Most objects that return a string intended for the user to see will provide a localized version. This will be translated into the user’s language, whenever possible. Look for these whenever you get a string that you’re going to showthe user. Here are some examples:
-[NSError localizedDescription]
-[UIDocument localizedName]
-[UIDevice localizedModel]
-[PKPass localizedName]
Dates and numbers, including currency, are formatted for the user’s region and personal preference. This cannot be inferred from their language; French speakers in France format currency differently than French speakers in Canada. In addition to the user’s region, iOS may provide personal preferences (such as a 12- or 24-hour clock) that the user can customize.
All of these variables and choices make correctly formatting values extremely challenging. Unless,
of course, you let iOS do it for you. Let me put it this way: always let iOS format dates and numbers; never try to do it yourself.
Let’s say you want to present a readable date and time to your user. Use the NSDateFormatter class to convert the date object into a displayable string, using the user’s desired language, calendar, and formatting style. This is such a common procedure that’s there’s even convenience method to do all of that with a single statement.
I created a simple demonstration app, named Dated, which you’ll find in the Learn iOS Development Projects ➤ Ch. 22 ➤ Dated folder. The Dated app presents a date picker and the results of converting that date into a readablestring using the NSDateFormatter class. Here’s the code in DTViewController.m that does all of the work:
self.dateView.text =
[NSDateFormatter localizedStringFromDate:self.datePicker.date dateStyle:NSDateFormatterFullStyle timeStyle:NSDateFormatterLongStyle];
When I first launch Dated in the simulator, as shown in the left in Figure 22-17, the date is in English, even though the current language is set to Español. That’s because dates, times, numbers, and currency are controlled by adifferent set of preferences—and another reason you can’t assume how numbers are formatted based on the user’s language.
Figure 22-17. Localizing dates using NSDateFormatter
In the Ajustes (Settings) app, I changed the Formato regional (Region Format) setting from Estados Unidos (United States) to España (Spain), as shown in the middle of Figure 22-17. Returning to the Dated app, both the apppicker and the formatted date have been translated to Spanish, using the date style conventions common in Spain.
Use NSNumberFormatter to format numbers, percentages, and currency. Both of these classes handle all of the subtle details. For more information, refer to the Data Formatting Guide that you can find in Xcode’s Documentationand API Reference window.
Localizing Your App’s Name
Your app’s .strings files are most often used to localize the string constants in your program, as you’ve already seen. They are, actually, general-purpose string translation files and are used for a variety of purposes, like translating the visible strings in the Settings.bundle.
One important .strings files is the InfoPlist.strings file, that’s localized automatically for you. The substitutions in this .strings file are applied to your app’s Info.plist file. This is the property list file that contains the information(metadata) about your app. You’ve edited this file earlier in the book, when you added device requirements like gps.
Expand the InfoPlist.strings group and select the InfoPlist.strings (Spanish) item. The InfoPlist.strings file contains substitutions for any user-visible property values contained in the Info.plist file. In iOS, this is pretty muchlimited to the name of your app. The keys of the
InfoPlist.strings file are not, however, the original strings; they’re the Info.plist property keys. To localize a specific property, add a property key and its localized value to your InfoPlist.strings file, like this:
"CFBundleDisplayName" = "Paloma";
For a Spanish speaking user, the app’s name becomes Paloma in the springboard, the Settings app, and elsewhere, as shown in Figure 22-18.
Figure 22-18. Localizing your app’s name
Summary
Localization is one of the last things you do to your app, but it certainly isn’t the least important. Localizing dramatically broadens your app’s horizons. And as you’ve seen, it’s not that much work. I’ll go so far as saying thatlocalizing your app is the single most significant step you can take to broaden its appeal.
While you’ve done all of the common steps, your app can support localization in more sophisticated, and non-standard, ways. It’s possible to switch languages within your own app, provide your own localization logic, or evenadd unsupported languages like Hawaiian or Klingon. Start with the Internationalization Programming Topics document that you can find in Xcode’s Documentation and API Reference window.
As localization is one of the last app development tasks you undertake, it’s fitting that this is one of the last chapters in this book. But your iOS journey doesn’t have to stop here. There’s so much more to perfect your app andrefine your app development skills. The next two chapters will improve your app’s performance, taking it to even greater heights.










No comments:
Post a Comment