你的位置:首页 > 操作系统

[操作系统]iOS Programming Localization 本地化


iOS Programming Localization 本地化

Internationalization is making sure your native cultural information is not hard-coded into your application.

国际化确保你的本土信息不是硬编码进你的应用。

By cultural information, we mean language, currency, date formats, number formats, and more.

说cultural information ,我们指的是language,currency,date formats ,number formats 等等。

Localization, on the other hand, is the process of providing the appropriate data in your application based on the user's Language and Region Format settings.

Localization 是提供恰当的数据在你的应用基于用户的语言,区域设置的过程。

You can find these settings in the Settings application. Select the General row and then the International row.

你可以找到这些信息在你的setting application .选择general 行,然后是international 行。

Apple makes these processes relatively simple.

apple 尽量让这个进程更简单。

An application that takes advantage of the localization APIs does not even need to be recompiled to be distributed in other languages or regions.

一个充分利用了localization APIs的应用甚至不需要重新编译来发布到另一个国家或地区 。

By the way, "internationalization" and "localization" are long words. You will sometimes see people abbreviate them to i18n and l10n, respectively.

internationalization 和localization 是长单词,人们经常缩写他们分别为i18n和l10n.

1 Internationalization Using NSNumberFormat

NSDateFormatter has a locale property, which is set to the device's current locale.

NSDateFormatter有一个locale property,它会设置为设备现在的locale.

Whenever you use an NSDateFormatter to create a date, it checks its locale property and sets the format accordingly. So the text of the date label has been internationalized from the start.

无论什么时候你用NSDateFormatter 创建一个date,它会检查他的locale property 并系相应的设置格式。所以date label 的text在一开始就被设置为国际化了。

NSLocale knows how different regions display symbols, dates, and decimals and whether they use the metric system.

NSLocale知道regions 之间显示symbols ,dates,decimals 和他们是否使用metric system 的区别。

An instance of NSLocale represents one region's settings for these variables. In the Settings application, the user can choose a region, like United States or United Kingdom.

When you send the message currentLocale to NSLocale, the instance of NSLocale that represents the user's region setting is returned. Once you have that instance of NSLocale, you can ask it questions like, "What is the currency symbol for this region?" or "Does this region use the metric system?"

当你发送currentLocale 信息给NSLocale时,NSLocale的实例代表了用户的region setting 。一旦你有了NSLocale的实例,你可以询问它问题例如"这个region 的currency symbol 是什么""这个region 是否使用metric system?"

To ask one of these questions, you send the NSLocale instance the message objectForKey: with one of the NSLocale constants as an argument.

为了询问这些问题中一个,你发送给NSLocale实例消息objectForKey用一个NSLocale 常量作为参数。

NSLocale *locale = [NSLocale currentLocale];

BOOL isMetric = [[locale objectForKey:NSLocaleUsesMetricSystem] boolValue];

NSString *currencySymbol = [locale objectForKey:NSLocaleCurrencySymbol];

 

 

While NSLocale is extremely powerful and useful, always using it directly would make the process of localizing apps very tedious. That's why you used NSDateFormatter earlier. There is another class, NSNumberFormatter that does for numbers what NSDateFormatter does for dates.

尽管NSLocale 极其强大和有用,总是用她,将使得localizing apps的处理变得非常枯燥。NSNumberFormatter就像NSDateFormmater 对dates.

 

Depending on the locale, the numberAsString may be 123,456.789 or 123 456,789 or some other value.

NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];

NSString *numberAsString = [numberFormatter stringFromNumber:@123456.789];

 

What makes NSNumberFormatter even more useful is its capability to format currency amounts. If the number formatter's numberStyle property is set to NSNumberFormatterCurrencyStyle, it will start producing the numbers formatted not only with the appropriate group and decimal separators, but also with the currency symbol.

使得NSNumberFormatter更有用的是它有能力格式化货币的amounts.如果number formatter 的numberStyle属性设置为NSNumberFormatterCurrencyStyle,它不仅产生相应的组合和小树分离,而且有currency symbol.

NSNumberFormatter *currencyFormatter = [[NSNumberFormatter alloc] init];

currencyFormatter.numberStyle = NSNumberFormatterCurrencyStyle;

NSString *numberAsString = [currencyFormatter stringFromNumber:@123456.789];

In BNRItemsViewController.m, locate the method tableView:cellForRowAtIndexPath:. Add the static variable currencyFormatter and set its numberStyle to NSNumberFormatterCurrencyStyle.

// Create a number formatter for currency

static NSNumberFormatter *currencyFormatter = nil;

if (currencyFormatter == nil) {

currencyFormatter = [[NSNumberFormatter alloc] init];

currencyFormatter.numberStyle = NSNumberFormatterCurrencyStyle;

}

When the text of the cell's valueLabel is set in this method, the string "$%d" is used, which makes the currency symbol always a dollar sign. Use the currencyFormatter to format the amount correctly.

cell.valueLabel.text = [currencyFormatter stringFromNumber:@(item.valueInDollars)];

These changes will display the value formatted appropriately for the user's region, with both the number format and currency symbol.

 

To make Homepwner update when the region settings change, you need to use NSNotificationCenter. In BNRItemsViewController's init

 method, register for locale change notifications:

为了让Homepwner更新当region settings 改变时,你需要使用NSNotificationCenter.在BNRItemsViewController's init方法里,注册locale change notifications .

 

// Register for locale change notifications

[nc addObserver:self

selector:@selector(localeChanged:) name:NSCurrentLocaleDidChangeNotification

object:nil];

 

Add the method localeChanged.

- (void)localeChanged:(NSNotification *)note

{
[self.tableView reloadData];

}

 

2 Localizing Resources 本地化资源

When internationalizing, you ask the instance of NSLocale questions. But the NSLocale only has a few region-specific variables. This is where localization comes into play: Localization is the process by which application-specific substitutions are created for different region and language settings.

当internationalizing,你询问NSLocale 实例的问题。但是NSLocale 仅仅有一些区域指定的变量。这也是localization怎么玩的。

Localization usually means one of two things:

(1)generating multiple copies of resources like images, sounds, and NIB files for different regions and languages

产生资源的倍数复制:像images,sounds,NIB files在不同的区域和语言。

(2)creating and accessing strings tables to translate text into different languages

创建和获取string 表来翻译text 为不同的语言。

Any resource, whether it is an image or a XIB file, can be localized.

任何资源不管它是image还是XIB文件,都能被本地化。

Localizing a resource puts another copy of the resource in the application bundle.

Localizing a resource 把资源的一个拷贝放在了application bundle.

These resources are organized into language- specific directories, known as lproj directories.

这些资源被组织放进language specific directories,称为lproj directories.

Each one of these directories is the name of the localization suffixed with lproj.

每一个这样的目录是以后缀lproj的本地化名字。

For example, the American English localization is en_US: where en is the English language code and US is the United States of America region code. (The region can be omitted if you do not need to make regional distinctions in your resource files.) These language and region codes are standard on all platforms, not just iOS.

例如,American English localization 是en_US.en 是English language code,US 是United Stated 区域code .

When a bundle is asked for the path of a resource file, it first looks at the root level of the bundle for a file of that name. If it does not find one, it looks at the locale and language settings of the device, finds the appropriate lproj directory, and looks for the file there. Thus, just by localizing resource files, your application will automatically load the correct file.

当一个bundle 被询问资源文件的path,它首先查看bundle 的根层级找到那个名字的文件。如果没有找到,它会查看locale 和language settings ,找到恰当的lproj 目录,寻找这个文件。因此,仅仅本地化resource files ,你的应用将自动的加载正确的文件。

One option is to create separate XIB files and to manually edit each string in this XIB file in Xcode. However, this approach does not scale well if you are planning multiple localizations. What happens when you add a new label or button to your localized XIB? You have to add this view to the XIB for every language. This is not fun.

 

To simplify the process of localizing XIB files, Xcode has a feature called Base internationalization. When it is enabled for the project, Base internationalization creates the Base.lproj directory which contains the main XIB files. Localizing individual XIB files can then be done by creating just the Localizable.strings files. It is still possible to create the full XIB files, in case localization cannot be done by changing strings alone. However, with the help of Auto Layout, strings replacement may be sufficient for most localization needs.

为了简化localizing XIB files的处理,Xcode有一个特性叫做Base internationalization.当它被这个project使用时,Base internationalization 创建了Base.lproj 目录,它包含了main XIB files .本地化独特的XIB 文件能够同故宫创建仅有的Localizable.strings files.这仍然是可能的创建full XIB files ,以防止localization 不能仅仅通过改变strings完成。然而,有Auto layout 的帮助,strings replacement 可能对大多数的localization neees 是足够的。

In this section, you are going to localize one of Homepwner's interfaces: the BNRDetailViewController.xib file. You will create English and Spanish localizations, which will create two lproj directories, in addition to the base one.

在本节中,你将localize 

BNRDetailViewController.xib文件。你将创建Englsih 和spanish localizations ,这将创建两个lproj 目录,除了基础的那个外。

Normally, you would first enable Base Internationalization in the project Info settings. However, as of this writing, there is a bug in Xcode that will not let you enable that option until at least one XIB file is localized.

一般的,你应该打开Base Internationalization 在project info settings .然而,在Xcode 中有一个bug,不让你选择直到一个XIB 文件已经localized .

So, start by localizing a XIB file. Select BNRDetailViewController.xib in the project navigator. Then, show the utility area.

Click the tab in the inspector selector to open the file inspector. Find the section in this inspector named Localization and click the Localize... button

Select English. This signifies to Xcode that this file can be localized, automatically creates en.lproj, and moves the BNRDetailViewController.xib file to it.

选择English.这个给Xcode 的信号是这个file能够被localized,自动的创建en.lproj,将BNRDetailViewController.xib移动到它当中。

Now you need to enable Base Internationalization.Make sure you select the project Homepwner, and not the target Homepwner.

现在你需要使Base Internationalization,确保你选择了Homepwner工程,而不是target.

In the bottom section of the Info tab of the project, locate the Use Base Internationalization checkbox in the Localizations section and check it. You will see the prompt to select which files will be used to create the Base localization; the table will consist of just BNRDetailViewController.xib and English will be listed as the reference language. Click Finish.

Click the + button under the list of languages and select Spanish. In the dialog, you can uncheck the InfoPlist.strings files and only keep the BNRDetailViewController.xib file checked. Make sure that the reference language is Base and the file type is Localizable Strings. Click Finish. This creates an es.lproj folder and generates the BNRDetailViewController.strings in it that contains all the strings from the base XIB file.

In the project navigator, click the Spanish version of BNRDetailViewController.strings. When this file opens, the text is not in Spanish. You have to translate localized files yourself; Xcode is not that smart.

Edit this file according to the following text. The numbers and order may be different in your file, but you can use the text field in the comment to match up the translations.

当打开BNRDetailViewController.strings文件时,text并不是spanish.你必须转换localized files 你自己。Xcode 并不是那么聪明。

编辑这个文件根据下面的文字。

3 NSLocalizedString() and Strings Tables    NSLocalizedString和Strings tabels

In many places in your applications, you create NSString instances dynamically or display string literals to the user. To display translated versions of these strings, you must create a strings table.

在许多地方,你动态的创建NSString实例或者展现string literals 给用户。为了展现这些strings 的翻译版本,你需要常见一个string table.

A strings table is a file containing a list of key-value pairs for all of the strings that your application uses and their associated translations. It is a resource file that you add to your application, but you do not need to do a lot of work to get data from it.

string table 是一个包含了一列key-value对的所有的strings 你的应用使用或他们相关的翻译。他是一个资源文件,但是你不需要做更多的事情来获取这些数据。

 

You might use a string in your code like this:

NSString *greeting = @"Hello!"

To internationalize the string in your code, you replace literal strings with the function NSLocalizedString.

NSString *greeting = NSLocalizedString(@"Hello!", @"The greeting for the user");

This function takes two arguments: a key and a comment that describes the string's use. The key is the lookup value in a strings table. At runtime, NSLocalizedString() will look through the strings tables bundled with your application for a table that matches the user's language settings. Then, in that table, the function gets the translated string that matches the key.

这个函数有两个参数:key和表述这个string 用途的comment.key 是在strings table 的查找值。在运行是,NSLocalizedString()将查找string tables bundled with 你的应用来找一个匹配用户语言设置的table.然后在这个table中,函数获得了匹配这个key的翻译。

Now you are going to internationalize the string "Homepwner" that is displayed in the navigation bar. In BNRItemsViewController.m, locate the init method and change the line of code that sets the title of the navigationItem.

navItem.title = NSLocalizedString(@"Homepwner", @"Name of application");

 

Two more view controllers contain hard-coded strings that can be internationalized. The toolbar in the BNRDetailViewController shows the asset type. The title of the BNRAssetTypeViewController needs to be updated just like the title of the BNRItemsViewController.

NSString *typeLabel = [self.item.assetType valueForKey:@"label"]; if (!typeLabel) {

typeLabel = @"None";

typeLabel = NSLocalizedString(@"None", @"Type label None"); }

 

self.assetTypeButton.title = [NSString stringWithFormat: NSLocalizedString(@"Type: %@", @"Asset type button"), typeLabel];

 

In BNRAssetTypeViewController.m, update the init method:

if (self) {
self.navigationItem.title = @"Asset Type"; self.navigationItem.title =

NSLocalizedString(@"Asset Type", @"BNRAssetTypeViewController title");

}

return self; }

Once you have files that have been internationalized with the NSLocalizedString function, you can generate strings tables with a command-line application.

一旦你的文件被internationalized 用NSLocalizedString 函数,你能用command-line 应用产生string tables .

Open the Terminal app.

In Terminal, type the following:

cd

followed by a space. 

Next, open Finder and locate BNRItemsViewController.m and the folder that contains it. Drag the icon

of that folder onto the Terminal window. Terminal will fill out the path for you. Press Enter.

 

To generate the strings table, enter the following into Terminal and press Enter:

为了产生string table,输入如下:

genstrings BNRItemsViewController.m

This creates a file named Localizable.strings in the same directory as BNRItemsViewController.m. Now you need to generate strings from the other two view controllers. Since the file Localizable.strings already exists, you will want to append to it, rather than create it from scratch.

这就会创造出Localizable.string 在和BNRItemViewController.m相同的目录下。现在你需要产生从另外两个view controller.因为Localizable.strings已经存在,你需要append to it 而不是重现创建它。

To do so, enter the following commands in the Terminal (do not forget the -a command line option) and press Enter after each line:

genstrings -a BNRDetailViewController.m

genstrings -a BNRAssetTypeViewController.m

The resulting file Localizable.strings now contains the strings from all three view controllers. Drag from the Finder into the project navigator (or use the Add Files to "Homepwner"... menu item). When the

application is compiled, this resource will be copied into the main bundle.

现在把他们拖动到project navigator中。

/* Name of application */

"Homepwner" = "Homepwner";

 

/* Type Label None */

"None" = "None";

 

/* Assert type button */

"Type:%@" = "Type:%@";

 

Oddly enough, Xcode sometimes has a problem with strings tables. Open the Localizable.strings file in the editor area. If you see a bunch of upside-down question marks, you need to reinterpret this file as Unicode (UTF-16). Show the utility area and select the file inspector. Locate the area named Text Settings and change the pop-up menu next to Text Encoding to Unicode (UTF-16) (Figure 25.10). It will ask if you want to reinterpret or convert. Choose Reinterpret.

Notice that the comment above your string is the second argument you supplied to the NSLocalizedString function. Even though the function does not require the comment argument, including it will make your localizing life easier.

注意到上面的comment是你提供的NSLocalizedString 函数的第二个参数。尽管这个函数不需要comment argument,包含它将使你localizing life 更容易。

Now that you have created Localizable.strings, localize it in Xcode the same way you did the XIB file. Select the file in the project navigator and click the Localize... button in the utility area. Add the Spanish localization and then open the Spanish version of Localizable.strings. The string on the lefthand side is the key that is passed to the NSLocalizedString function, and the string on the righthand side is what is returned. Change the text on the righthand side to the Spanish translation shown below.

现在你创建了Localizable.strings,localize 它在Xcode中。选择Localize...button。添加Spanish localization 并打开Spanish 版本的LOcalizable.strings.左侧是key,右侧是你想返回的值。

/* Name of application */

"Homepwner" = "Dueño de casa";

 

/* Type Label None */

"None" = "Nada";

 

/* Assert type button */

"Type:%@" = "Tipo:%@";