Wednesday, 7 May 2014

Using the genstrings Tool [Êtes-vous Polyglotte?]

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 Xs 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 projectin 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 shells 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 shells 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 isnt 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), ashown 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 theres 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.storyboardWith 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 users 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

 Heres how it works. The NSLocalizedString... macros expand into code that sends a -localized StringForKey:value:table: message to the apps 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 cant 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 stringfile for thaInterface Builder file, named Main_iPhone.strings. The file would have contained substitutionfor various text properties (mostlycontrol titles) of the view objects in that interface, like thione:

"jkj-WQ-xYm.title" = "Remember Location";

The key is an identifier that only Interface Builder and iOS understand; dont change it. In this instance, it identifiers the bar button items 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 Pigeons resources is the Settings.bundle that defines its settings in the Settings app. Its a bundle, like your apps 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. Its 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. Lets 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 doesnt manage localized files inside other bundles, so you’llhave to create the Spanish localization manually. Its 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 navigatorselect the Root.strings file, and edit it as follows 
(new text in bold):

"Sync  Locations" = "Actualizar Ubicaciónes";

Run Pigeon. Afteit starts, presthe hombutton antap the Settings app—oops, I mean the Ajusteapp. 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 users 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 users 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 users 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.

Lets 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 users desired language, calendar, and formatting style. This is such a common procedure thats theres 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. Heres 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. Thats because dates, times, numbers, and currency are controlled by adifferent set of preferences—and another reason you cant assume how numbers are formatted based on the users 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 Xcodes Documentationand API Reference window.

Localizing Your Apps Name

Your apps .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, thats localized automatically for you. The substitutions in this .strings file are applied to your apps 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.stringfile are not, however, the original strings; they’re the Info.plist property keysTo 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 apps name becomes Paloma in the springboard, the Settings app, and elsewhere, as shown in Figure 22-18.


Figure 22-18. Localizing your apps name

Summary

Localization is one of the last things you do to your app, but it certainly isnt the least important. Localizing dramatically broadens your apps horizons. And as you’ve seen, its 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. Its 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 Xcodes Documentation and API Reference window.

As localization is one of the last app development tasks you undertake, its fitting that this is one of the last chapters in this book. But your iOS journey doesnt have to stop here. Theres so much more to perfect your app andrefine your app development skills. The next two chapters will improve your apps performance, taking it to even greater heights.

No comments:

Post a Comment