MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Objective-C 在 Mac OS 应用国际化与本地化中的应用

2024-09-044.0k 阅读

国际化与本地化概述

在当今全球化的市场环境下,Mac OS 应用程序需要支持多种语言和地区设置,以满足不同用户群体的需求。国际化(Internationalization,简称 i18n)是指设计和开发应用程序,使其能够适应不同语言、地区和文化的过程。本地化(Localization,简称 l10n)则是针对特定语言、地区或文化对应用程序进行定制的过程,包括翻译文本、调整日期和数字格式、适配图像和图标等。

Objective - C 作为 Mac OS 开发的重要编程语言,提供了丰富的工具和技术来实现应用的国际化与本地化。通过使用这些功能,开发者可以创建出能够无缝适应全球用户的高质量应用程序。

Objective - C 中的本地化资源

在 Objective - C 开发中,本地化资源主要通过 Strings 文件和 NIB/XIB 文件来管理。

Strings 文件

Strings 文件是用于存储本地化字符串的文本文件。每个语言对应一个独立的 Strings 文件,文件名格式为 Localizable.strings,存放在对应的语言包目录下。例如,英语的 Localizable.strings 文件路径可能是 Base.lproj/Localizable.strings,法语的则在 fr.lproj/Localizable.strings

Strings 文件中,键值对形式存储字符串。键是应用程序中使用的标识符,值是对应语言的翻译文本。例如:

"greeting" = "Hello"; // 在 Base.lproj/Localizable.strings 中
"greeting" = "Bonjour"; // 在 fr.lproj/Localizable.strings 中

在 Objective - C 代码中,可以使用 NSLocalizedString 宏来获取本地化字符串。例如:

NSString *greeting = NSLocalizedString(@"greeting", @"A simple greeting");

NSLocalizedString 宏的第一个参数是 Strings 文件中的键,第二个参数是注释,用于帮助翻译人员理解该字符串的用途。

NIB/XIB 文件

NIB(NeXT Interface Builder)或 XIB(XML Interface Builder)文件用于定义用户界面。在国际化过程中,可以对 NIB/XIB 文件进行本地化,使其能够显示不同语言的界面元素。

当创建一个新的 NIB/XIB 文件时,Xcode 会默认创建一个基础版本(通常是英文)。要添加其他语言的本地化版本,可以在项目导航器中选中 NIB/XIB 文件,在属性检查器中点击 “Localize...” 按钮,然后选择要支持的语言。

Xcode 会为每个选中的语言创建一个对应的 lproj 目录,并在其中复制 NIB/XIB 文件。在这些本地化的 NIB/XIB 文件中,可以分别设置界面元素的文本,例如按钮标题、标签文本等,以适应不同语言的显示需求。

日期和数字格式的本地化

除了文本字符串,日期和数字格式也需要根据用户所在地区进行本地化。Objective - C 提供了 NSDateFormatterNSNumberFormatter 类来实现这一功能。

NSDateFormatter

NSDateFormatter 用于将 NSDate 对象格式化为字符串,或者将字符串解析为 NSDate 对象。可以通过设置 dateStyletimeStyle 属性来指定日期和时间的显示格式。

例如,要以本地化格式显示当前日期:

NSDate *currentDate = [NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
[dateFormatter setTimeStyle:NSDateFormatterNoStyle];
NSString *localizedDateString = [dateFormatter stringFromDate:currentDate];
NSLog(@"Localized Date: %@", localizedDateString);

上述代码中,NSDateFormatterMediumStyle 会根据用户的地区设置,以适中的格式显示日期。如果用户在法国,日期可能会显示为 “15 août 2023”,而在美国可能显示为 “Aug 15, 2023”。

NSNumberFormatter

NSNumberFormatter 用于格式化和解析数字。可以设置 numberStyle 属性来指定数字的显示风格,如货币格式、百分比格式等。

例如,要以本地化货币格式显示一个数字:

NSNumber *amount = @1234.56;
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
NSString *localizedCurrencyString = [numberFormatter stringFromNumber:amount];
NSLog(@"Localized Currency: %@", localizedCurrencyString);

在不同地区,货币格式会有所不同。例如,在美国可能显示为 “$1,234.56”,在欧洲可能显示为 “1 234,56 €”。

处理图像和图标本地化

对于应用中的图像和图标,也需要进行本地化处理,以适应不同文化背景的用户。

图像命名约定

一种常见的方法是使用图像命名约定。可以在图像文件名中添加语言或地区代码后缀。例如,对于一个通用的图标文件 icon.png,可以创建 icon_fr.png 用于法语地区,icon_de.png 用于德语地区等。

在代码中加载图像时,可以根据当前系统语言或用户设置来选择合适的图像文件。例如:

NSString *languageCode = [[NSLocale preferredLanguages] firstObject];
NSString *imageName = [NSString stringWithFormat:@"icon_%@.png", languageCode];
UIImage *localizedImage = [UIImage imageNamed:imageName];
if (!localizedImage) {
    localizedImage = [UIImage imageNamed:@"icon.png"]; // 备用通用图像
}

上述代码首先尝试加载特定语言的图像,如果找不到,则加载通用图像。

Asset Catalog

Xcode 的 Asset Catalog 也支持图像本地化。可以在 Asset Catalog 中选中图像集,然后在属性检查器中点击 “+” 按钮添加不同语言的变体。Xcode 会根据运行时的语言设置自动加载相应的图像。

应用程序的本地化设置

为了使应用程序能够正确地进行本地化,需要在项目设置中进行一些配置。

设置支持的语言

在 Xcode 项目导航器中,选中项目文件,在 “Info” 选项卡中找到 “Localizations” 部分。点击 “+” 按钮添加应用程序支持的语言。Xcode 会为每个添加的语言创建对应的 lproj 目录,并将需要本地化的资源文件复制到相应目录下。

设置应用程序的本地化标识符

在项目设置的 “Info” 选项卡中,找到 “CFBundleDevelopmentRegion” 键,设置其值为应用程序的开发语言,通常是英语。这个设置会影响应用程序在没有找到特定语言的本地化资源时,默认使用哪种语言的资源。

本地化 Info.plist 文件

Info.plist 文件包含了应用程序的一些元数据,如应用名称、版本号等。可以对 Info.plist 文件进行本地化,使其在不同语言环境下显示不同的应用名称。

在项目导航器中选中 Info.plist 文件,点击 “Localize...” 按钮,选择要本地化的语言。Xcode 会为每个选中的语言创建一个 InfoPlist.strings 文件,在其中可以设置本地化的 CFBundleDisplayName(应用显示名称)等键值对。例如:

"CFBundleDisplayName" = "My App"; // 在 Base.lproj/InfoPlist.strings 中
"CFBundleDisplayName" = "Mon App"; // 在 fr.lproj/InfoPlist.strings 中

示例应用:简单的多语言计算器

下面通过一个简单的计算器应用示例,详细展示 Objective - C 在 Mac OS 应用国际化与本地化中的应用。

创建项目

首先,在 Xcode 中创建一个新的 Mac OS 应用项目,选择 “App - Cocoa Application” 模板,命名为 “MultilingualCalculator”。

设计用户界面

打开 MainMenu.xib 文件,设计一个简单的计算器界面,包含数字按钮、运算符按钮、结果显示标签等。将界面元素的文本设置为英文,作为基础版本。

本地化用户界面

  1. 选中 MainMenu.xib 文件,在属性检查器中点击 “Localize...” 按钮,添加法语和德语本地化。
  2. 打开 fr.lproj/MainMenu.xib 文件,将按钮和标签的文本翻译为法语。同样,在 de.lproj/MainMenu.xib 文件中,将文本翻译为德语。

本地化字符串

  1. 在项目导航器中,创建一个新的文件,选择 “Strings File”,命名为 Localizable.strings。Xcode 会自动将其放置在 Base.lproj 目录下。
  2. Base.lproj/Localizable.strings 文件中,添加如下内容:
"result_label" = "Result";
"error_message" = "Error";
  1. fr.lproj/Localizable.strings 文件中添加法语翻译:
"result_label" = "Résultat";
"error_message" = "Erreur";
  1. de.lproj/Localizable.strings 文件中添加德语翻译:
"result_label" = "Ergebnis";
"error_message" = "Fehler";

代码实现

打开 AppDelegate.h 文件,添加以下属性:

@property (weak) IBOutlet NSTextField *resultLabel;

打开 AppDelegate.m 文件,在 applicationDidFinishLaunching: 方法中加载本地化字符串:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    self.resultLabel.stringValue = NSLocalizedString(@"result_label", @"Label for result display");
}

假设计算器有一个计算方法 calculate,在计算出错时显示本地化的错误信息:

- (void)calculate {
    // 计算逻辑
    if (hasError) {
        NSString *errorMessage = NSLocalizedString(@"error_message", @"Error message when calculation fails");
        NSAlert *alert = [NSAlert alertWithMessageText:errorMessage
                                         defaultButton:@"OK"
                                       alternateButton:nil
                                           otherButton:nil
                             informativeTextWithFormat:@""];
        [alert runModal];
    }
}

运行和测试

在 Xcode 中选择不同的模拟器语言(法语、德语或英语),运行应用程序。可以看到界面元素的文本会根据所选语言自动切换,并且在计算出错时显示相应语言的错误信息。

处理复杂的本地化场景

在实际应用开发中,可能会遇到一些复杂的本地化场景,需要更细致的处理。

动态语言切换

有些应用程序允许用户在运行时切换语言。要实现这一功能,可以通过监听系统语言变化通知,或者提供一个自定义的语言切换按钮。

例如,监听系统语言变化通知:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(languageChanged:)
                                             name:NSCurrentLocaleDidChangeNotification
                                           object:nil];

languageChanged: 方法中,重新加载本地化字符串和更新界面:

- (void)languageChanged:(NSNotification *)notification {
    self.resultLabel.stringValue = NSLocalizedString(@"result_label", @"Label for result display");
    // 其他需要更新的界面元素
}

复数和性别化语言处理

一些语言有复数形式和性别化语法。在 Strings 文件中,可以使用复数格式和占位符来处理这些情况。

例如,在英语中,“There is 1 item” 和 “There are 2 items” 是不同的表达。在 Strings 文件中,可以这样定义:

"item_count_format" = "There is %d item";
"item_count_format_plural" = "There are %d items";

在代码中使用 NSLocalizedStringWithDefaultValue 宏来获取正确的字符串:

int itemCount = 5;
NSString *itemCountString = NSLocalizedStringWithDefaultValue(@"item_count_format",
                                                              @"Localizable",
                                                              [NSBundle mainBundle],
                                                              (itemCount == 1? @"item_count_format" : @"item_count_format_plural"),
                                                              @"Format string for item count");
itemCountString = [NSString stringWithFormat:itemCountString, itemCount];

对于性别化语言,如法语中 “le” 用于阳性名词,“la” 用于阴性名词,可以通过类似的方式,根据具体情况选择合适的翻译字符串。

本地化测试

本地化测试是确保应用程序在不同语言和地区环境下正常运行的关键步骤。

手动测试

手动测试是最基本的本地化测试方法。在 Xcode 模拟器或实际设备上,将系统语言设置为应用支持的各种语言,逐个测试应用的各个功能,检查界面文本是否正确翻译、日期和数字格式是否符合当地习惯、图像和图标是否显示正常等。

自动化测试

可以使用一些自动化测试工具来辅助本地化测试。例如,使用 XCTest 框架编写测试用例,验证本地化字符串是否正确加载,日期和数字格式是否符合预期等。

例如,编写一个测试用例来验证本地化字符串:

#import <XCTest/XCTest.h>

@interface LocalizationTests : XCTestCase

@end

@implementation LocalizationTests

- (void)testLocalizedString {
    NSString *greeting = NSLocalizedString(@"greeting", @"A simple greeting");
    XCTAssertNotNil(greeting, @"Localized string should not be nil");
}

@end

通过自动化测试,可以快速发现本地化相关的问题,提高测试效率和准确性。

与其他框架和技术的集成

在实际项目中,Objective - C 应用可能会与其他框架和技术集成,如网络请求框架、数据存储框架等。在国际化和本地化过程中,需要确保这些集成部分也能正确支持不同语言和地区。

网络请求

如果应用通过网络请求获取数据,并且数据中包含需要本地化的内容,服务器端可能需要根据客户端发送的语言信息返回相应语言的数据。客户端在发送请求时,可以在请求头中添加 Accept - Language 字段,告知服务器客户端支持的语言。

例如,使用 NSURLSession 发送网络请求:

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://example.com/api/data"]];
[request setValue:[[NSLocale preferredLanguages] componentsJoinedByString:@","] forHTTPHeaderField:@"Accept - Language"];
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
    // 处理响应数据
}];
[task resume];

数据存储

当应用需要存储本地化数据时,如用户设置的语言偏好等,可以使用 NSUserDefaults 或其他数据存储框架。在存储和读取数据时,要确保数据的一致性和兼容性。

例如,存储用户选择的语言:

NSString *selectedLanguage = @"fr"; // 用户选择的法语
[[NSUserDefaults standardUserDefaults] setObject:selectedLanguage forKey:@"selectedLanguage"];
[[NSUserDefaults standardUserDefaults] synchronize];

在应用启动时读取用户选择的语言,并根据其设置应用的语言环境:

NSString *selectedLanguage = [[NSUserDefaults standardUserDefaults] objectForKey:@"selectedLanguage"];
if (selectedLanguage) {
    NSArray *languages = @[selectedLanguage];
    [[NSUserDefaults standardUserDefaults] setObject:languages forKey:@"AppleLanguages"];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

通过以上对 Objective - C 在 Mac OS 应用国际化与本地化中的应用介绍,从资源管理、日期数字格式处理、图像本地化、应用设置到复杂场景处理、测试以及与其他技术的集成,开发者可以全面掌握如何创建一个能够满足全球用户需求的高质量 Mac OS 应用程序。在实际开发中,应根据应用的具体需求和目标用户群体,灵活运用这些技术和方法,确保应用在不同语言和地区环境下都能提供良好的用户体验。