在大多数国家,英语不是母语,当然我们汉语也不是母语。即使在某个国家,有些人使用汉语或英语,最好的方式还是用客户的母语来展现应用程序。用户如果选择汉语,那没别的了。但如果选择英语,这时候英语又会有英式英语、美式英语、澳大利亚英语、加拿大英语等,它们各有差异。
IOS提供了一些方法来本地化整个屏幕、一些或全部字符串,甚至只是一幅单独的图像。归因于自动布局,大多数应用程序可以专注于字符串或更新一些布局约束。
在接下来的章节里,我们将尝试向CarValet应用程序再添加两种语言,并寻找其中的约束可能需要修改的地方。
正文开始
首先先练练手,在ViewController.m中进行如下修改
- (void)displayCurrentCarInfo {
Car *currentCar;
currentCar = [arrayOfCars objectAtIndex:displayedCarIndex];
self.CarInfoLabel.text = currentCar.carInfo;
[self updateLabel:self.CarNumberLabel withBaseString:NSLocalizedString(@"Car Number",@"Label for the total number of current car")
count:displayedCarIndex +1];
}
- (IBAction)newCar:(id)sender {
Car *newCar = [[Car alloc] init];
[arrayOfCars addObject:newCar];
[self updateLabel:self.totalCarsLabel withBaseString:NSLocalizedString(@"Total Cars", @"Label for the total number of cars")
count:[arrayOfCars count]];
}
在终端中快速打开
然后输入genstrings -o Base.lproj *.m
会出现Localizable.strings的一个文件,现在把他拉到项目中。如图(PS 你们的应该是没有倒三角的,我这是之后添加其他东西的图)
Localizable.strings文件内容如下:
Localizable.strings文件中的每一条对应一个唯一的用NSlocalizedString定义的字符串。键与第一个参数相同,并且注释也与第二个参数一致。这个文件中有一些结果字符串竟然和键相同,这可能看起来很奇怪,但那时因为这是英语本地化的结果。对于汉语的话,应该是这个样子的
"Car Number" = "车辆数目";
在这里我们最好使用描述性的键。作如下修改
- (void)displayCurrentCarInfo {
Car *currentCar;
currentCar = [arrayOfCars objectAtIndex:displayedCarIndex];
self.CarInfoLabel.text = currentCar.carInfo;
[self updateLabel:self.CarNumberLabel withBaseString:NSLocalizedStringWithDefaultValue(@"CarNumberLabel",nil,[NSBundle mainBundle],@"Car Number",@"Label for the total number of current car") count:displayedCarIndex +1];
}
- (IBAction)newCar:(id)sender {
Car *newCar = [[Car alloc] init];
[arrayOfCars addObject:newCar];
[self updateLabel:self.totalCarsLabel withBaseString:NSLocalizedStringWithDefaultValue(@"TotalCarsLabel",nil,[NSBundle mainBundle],@"Total Cars",@"Label for the total number of cars") count:[arrayOfCars count]];
}
这时候再genstrings -o Base.lproj *.m
变成下面的图
可以试着改一下变成"CarNumberLabel" = "Car Numberasdasd"
你会发现在模拟器中他变了。
接下来我们要本地化其他的标签或按钮
首先为New Car按钮
命名为addCarButton
使用同样的方法创建previousCarButton/nextCarButton和editCarButton
完成之后,修改ViewController.m文件中的viewDidLoad方法中的变化
- (void)viewDidLoad {
[super viewDidLoad];
NSString *local;//为当前的本地化标题设置临时字符串引用
//将这个临时字符串设置为Add Car按钮的本地化标题
local = NSLocalizedStringWithDefaultValue(@"NewCarButton", nil, [NSBundle mainBundle], @"New Car", @"Button to create and add a new car");
[self.addCarButton setTitle:local forState:UIControlStateNormal];//将Add Car按钮在默认状态下的标题设置为这个本地化字符串
local = NSLocalizedStringWithDefaultValue(@"PreviousCarButton", nil, [NSBundle mainBundle], @"Previous", @"Title for button to go to the previous car");
[self.previousCarButton setTitle:local forState:UIControlStateNormal];
local = NSLocalizedStringWithDefaultValue(@"NextCarButton", nil, [NSBundle mainBundle], @"Next", @"Title for button to go to the next car");
[self.nextCarButton setTitle:local forState:UIControlStateNormal];
local = NSLocalizedStringWithDefaultValue(@"EditCarButton", nil, [NSBundle mainBundle], @"Edit", @"Title for button to edit the current car");
[self.editCarButton setTitle:local forState:UIControlStateNormal];
arrayOfCars = [[NSMutableArray alloc] init];//初始化汽车的数组为空数组
displayedCarIndex = 0;//显示创建的第一辆汽车
[self setupLandscapeConstraints];
UIInterfaceOrientation currOrientation = [[UIApplication sharedApplication]statusBarOrientation];
isShowingPortrait = UIInterfaceOrientationIsPortrait(currOrientation);
}
然后再次genstrings -o Base.lproj *.m
Car对象从carInfo方法返回用于显示的字符串。该方法目前基于一个简单的格式字符串,其中的标题、分隔符、类别、占位符值和年份都是硬编码值。现在,可以向各市字符串添加元素来进行本地化了。
Car.m文件中新的carInfo:方法
- (NSString *)carInfo {
NSString *infoLabel = NSLocalizedStringWithDefaultValue(@"CarInfoLabel", nil, [NSBundle mainBundle], @"Car Info", @"Label for the information of one car");
NSString *makeLabel = NSLocalizedStringWithDefaultValue(@"CarInfoMakeLabel", nil, [NSBundle mainBundle], @"Make ", @"Make Label for the make of one car");
NSString *modelLabel = NSLocalizedStringWithDefaultValue(@"CarInfoModelLabel", nil, [NSBundle mainBundle], @"Model", @"Model label for the model of one car");
NSString *yearLabel = NSLocalizedStringWithDefaultValue(@"CarInfoYearLabel", nil, [NSBundle mainBundle], @"Year", @"Year label for one car");
NSString *unknownMake = NSLocalizedStringWithDefaultValue(@"UnknownMakePlaceholder", nil, [NSBundle mainBundle], @"Unknown Make", @"Placeholder string for an unknown car make");
NSString *unknownModel = NSLocalizedStringWithDefaultValue(@"UnknownModelPlaceholder", nil, [NSBundle mainBundle], @"Unknown Model", @"Placeholder string for an unknown car model");
return [NSString stringWithFormat:@"%@\n %@: %@\n %@: %@\n %@: %d",
infoLabel,makeLabel,
self.make ? self.make : unknownMake,
modelLabel,
self.model ? self.model : unknownModel,
yearLabel,self.year];
}
再次genstrings -o Base.lproj *.m
最后,我们要为编辑汽车场景设置本地化:
属性名称 | 文本框 |
---|---|
CarMakeFieldLabel | Make文本框旁边的标签 |
CarModelFieldLabel | Model文本框旁边的标签 |
CarYearFieldLabel | Year文本框旁边的标签 |
CarFuelFieldLabel | Fuel文本框旁边的标签 |
上表是我们将编辑汽车场景中的四个标签拉到CarEditViewController.h中的名称,方法就不再细说了。最后代码应该如下
#import <UIKit/UIKit.h>
#import "CarEditViewControllerProtocol.h"
@class Car;
@interface CarEditViewController : UIViewController
//
//@property (nonatomic) NSInteger carNumber;
@property (weak, nonatomic) id <CarEditViewControllerProtocol> delegate;
@property (strong,nonatomic) Car *currentCar;
@property (weak, nonatomic) IBOutlet UILabel *carNumberLabel;
@property (weak, nonatomic) IBOutlet UILabel *CarMakeFieldLabel;
@property (weak, nonatomic) IBOutlet UILabel *CarModelFieldLabel;
@property (weak, nonatomic) IBOutlet UILabel *CarYearFieldLabel;
@property (weak, nonatomic) IBOutlet UILabel *CarFuelFieldLabel;
@property (weak, nonatomic) IBOutlet UITextField *makeField;
@property (weak, nonatomic) IBOutlet UITextField *modelField;
@property (weak, nonatomic) IBOutlet UITextField *yearField;
@property (weak, nonatomic) IBOutlet UITextField *fuelField;
@end
现在修改CarEditViewController.m文件中viewDidLoad方法
- (void)viewDidLoad {
[super viewDidLoad];
NSString *labelFormat = @"%@:";//为标签设置默认的格式字符串,其中包含分隔符。这允许后续使用NSlocalizedString宏来对格式字符串进行本地化
NSString *local;//设置一个临时变量,用于存储指向每一个本地化字符串对象的指针,然后设置UI元素要显示的字符串。可以跳过使用变量,将接卖弄字符串设置为调用NSLocalizedStringWithDefaultValue的返回值
//格式化所有标签
local = NSLocalizedStringWithDefaultValue(@"CarMakeFieldLabel", nil, [NSBundle mainBundle], @"Make", "Label for the line to enter or edit the Make of a car");
self.CarMakeFieldLabel.text = [NSString stringWithFormat:labelFormat,local];
local = NSLocalizedStringWithDefaultValue(@"CarModelFieldLabel", nil, [NSBundle mainBundle], @"Model", @"Label for the line to enter or edit the Model of a car");
self.CarModelFieldLabel.text = [NSString stringWithFormat:labelFormat,local];
local = NSLocalizedStringWithDefaultValue(@"CarYearFieldLabel", nil, [NSBundle mainBundle], @"Year", @"Label for the line to enter or edit the Year of a car");
self.CarYearFieldLabel.text = [NSString stringWithFormat:labelFormat,local];
local = NSLocalizedStringWithDefaultValue(@"CarFuelFieldLabel", nil, [NSBundle mainBundle], @"Fuel", @"Label for the line to enter or edit the Fuel of a car");
self.CarFuelFieldLabel.text = [NSString stringWithFormat:labelFormat,local];
NSString *carNumberText;
//格式化Car Number标签。与Add/View场景使用相同的键
carNumberText = [NSString stringWithFormat:@"%@: %ld",
NSLocalizedString(@"CarNumberLabel", @"Label for the index number of the current car"),(long)[self.delegate carNumber]];
self.carNumberLabel.text = carNumberText;
self.currentCar = [self.delegate carToEdit];
self.makeField.text = self.currentCar.make;
self.modelField.text = self.currentCar.model;
self.yearField.text = [NSString stringWithFormat:@"%d",self.currentCar.year];
self.fuelField.text = [NSString stringWithFormat:@"%0.2f",self.currentCar.fuelAmount];
}
再次genstrings -o Base.lproj *.m
PS可能出现的问题是Localizable.strings文件没有变化,我是出现这种情况了,找半天没办法,只能手动输入,亲测也是可以的,下面给出最后的Localizable.strings代码
/* Label for the information of one car */
"CarInfoLabel" = "Car Info";
/* Make Label for the make of one car */
"CarInfoMakeLabel" = "Make ";
/* Model label for the model of one car */
"CarInfoModelLabel" = "Model";
/* Year label for one car */
"CarInfoYearLabel" = "Year";
/* Label for the total number of current car */
"CarNumberLabel" = "Car Number";
/* Title for button to edit the current car */
"EditCarButton" = "Edit";
/* Button to create and add a new car */
"NewCarButton" = "New Car";
/* Title for button to go to the next car */
"NextCarButton" = "Next";
/* Title for button to go to the previous car */
"PreviousCarButton" = "Previous";
/* Label for the total number of cars */
"TotalCarsLabel" = "Total Cars";
/* Placeholder string for an unknown car make */
"UnknownMakePlaceholder" = "Unknown Make";
/* Placeholder string for an unknown car model */
"UnknownModelPlaceholder" = "Unknown Model";
/* Label for the line to enter or edit the Make of a car */
"CarMakeFieldLabel" = "Make";
/* Label for the line to enter or edit the Model of a car */
"CarModelFieldLabel" = "Model";
/* Label for the line to enter or edit the Year of a car */
"CarYearFieldLabel" = "Year";
/* Label for the line to enter or edit the Fuel of a car */
"CarFuelFieldLabel" = "Fuel";
好了,现在我们把要变的名称都设好键了。开始添加新的语言区域。我们首先当然是添加中文区域。先添加一个简体中文。
(PS:你可能会发现并没有InfoPlist.Strings,没关系,我们可以自己创建一个)
首先创建一个文件
选中Strings File 并命名为InfoPlist.strings,然后拉到文件中(或本来就在里面了)
这边我又创建一个文件来说明一下(上面那个是最后结果)
先假装左边的圈圈是InfoPlist.strings,然后点右边的圈圈,会出现
选择Chinese
然后会如下图(出现三角形了)
将旁边那些除了base都选上。在中文的那个文件里面(就是写了Chinese的那个文件,输入CFBundleDisplayName = "汽车管理程序";
然后你把手机调成中文或模拟器的设置里面调成中文。运行,回到桌面
变成中文了。所以这里的CFBundleDisplayName
表示的是桌面的名称。
现在我们来修改里面的内容
Localizable.strings中选中中文的那个文件
不想敲代码的话可以复制下面的内容:
/* Label for the information of one car */
"CarInfoLabel" = "车辆信息";
/* Make Label for the make of one car */
"CarInfoMakeLabel" = "品牌";
/* Model label for the model of one car */
"CarInfoModelLabel" = "型号";
/* Year label for one car */
"CarInfoYearLabel" = "生产日期";
/* Label for the total number of current car */
"CarNumberLabel" = "当前车号";
/* Title for button to edit the current car */
"EditCarButton" = "编辑";
/* Button to create and add a new car */
"NewCarButton" = "新添一辆车";
/* Title for button to go to the next car */
"NextCarButton" = "下一辆";
/* Title for button to go to the previous car */
"PreviousCarButton" = "上一辆";
/* Label for the total number of cars */
"TotalCarsLabel" = "总车数";
/* Placeholder string for an unknown car make */
"UnknownMakePlaceholder" = "未知品牌";
/* Placeholder string for an unknown car model */
"UnknownModelPlaceholder" = "未知型号";
/* Label for the line to enter or edit the Make of a car */
"CarMakeFieldLabel" = "品牌";
/* Label for the line to enter or edit the Model of a car */
"CarModelFieldLabel" = "型号";
/* Label for the line to enter or edit the Year of a car */
"CarYearFieldLabel" = "生产日期";
/* Label for the line to enter or edit the Fuel of a car */
"CarFuelFieldLabel" = "耗油量";
这时候在运行。贴上四张图
发现一开始是没有全会中文的,还有一些英文在捣乱,而且编辑汽车的时候,发现标签没有完全显示出来。这不是我梦想要的,所以接下来我们还得改。
(PS当然你还可以在试着添加几门语言进去玩一下)
好了,言归正传,现在开始修改主页的英文,修改ViewController.m的ViewDidLoad方法
- (void)viewDidLoad {
[super viewDidLoad];
self.title = NSLocalizedStringWithDefaultValue(@"AddViewScreenTitle", nil, [NSBundle mainBundle], @"CarValet", "Title for the main app screen");
NSString *local;//为当前的本地化标题设置临时字符串引用
//将这个临时字符串设置为Add Car按钮的本地化标题
local = NSLocalizedStringWithDefaultValue(@"NewCarButton", nil, [NSBundle mainBundle], @"New Car", @"Button to create and add a new car");
[self.addCarButton setTitle:local forState:UIControlStateNormal];//将Add Car按钮在默认状态下的标题设置为这个本地化字符串
local = NSLocalizedStringWithDefaultValue(@"PreviousCarButton", nil, [NSBundle mainBundle], @"Previous", @"Title for button to go to the previous car");
[self.previousCarButton setTitle:local forState:UIControlStateNormal];
local = NSLocalizedStringWithDefaultValue(@"NextCarButton", nil, [NSBundle mainBundle], @"Next", @"Title for button to go to the next car");
[self.nextCarButton setTitle:local forState:UIControlStateNormal];
local = NSLocalizedStringWithDefaultValue(@"EditCarButton", nil, [NSBundle mainBundle], @"Edit", @"Title for button to edit the current car");
[self.editCarButton setTitle:local forState:UIControlStateNormal];
arrayOfCars = [[NSMutableArray alloc] init];//初始化汽车的数组为空数组
displayedCarIndex = 0;//显示创建的第一辆汽车
[self setupLandscapeConstraints];
UIInterfaceOrientation currOrientation = [[UIApplication sharedApplication]statusBarOrientation];
isShowingPortrait = UIInterfaceOrientationIsPortrait(currOrientation);
}
对CarEditViewController.m进行同样的操作,使用键EditViewScreenTitle,默认值为”Edit Car”,在中文的那个文件里面写”编辑汽车”(或随便啦)
其余的两个车辆信息跟车辆总数和当前车辆,那个就交给你们自己试一下吧。(如果没有试出来可以在下面看到代码,记得要加键)
- (void)viewDidLoad {
[super viewDidLoad];
self.title = NSLocalizedStringWithDefaultValue(@"AddViewScreenTitle", nil, [NSBundle mainBundle], @"CarValet", "Title for the main app screen");
NSString *local;//为当前的本地化标题设置临时字符串引用
//将这个临时字符串设置为Add Car按钮的本地化标题
local = NSLocalizedStringWithDefaultValue(@"NewCarButton", nil, [NSBundle mainBundle], @"New Car", @"Button to create and add a new car");
[self.addCarButton setTitle:local forState:UIControlStateNormal];//将Add Car按钮在默认状态下的标题设置为这个本地化字符串
local = NSLocalizedStringWithDefaultValue(@"PreviousCarButton", nil, [NSBundle mainBundle], @"Previous", @"Title for button to go to the previous car");
[self.previousCarButton setTitle:local forState:UIControlStateNormal];
local = NSLocalizedStringWithDefaultValue(@"NextCarButton", nil, [NSBundle mainBundle], @"Next", @"Title for button to go to the next car");
[self.nextCarButton setTitle:local forState:UIControlStateNormal];
local = NSLocalizedStringWithDefaultValue(@"EditCarButton", nil, [NSBundle mainBundle], @"Edit", @"Title for button to edit the current car");
[self.editCarButton setTitle:local forState:UIControlStateNormal];
local = NSLocalizedStringWithDefaultValue(@"TotalNumber", nil, [NSBundle mainBundle], @"Total Car", @"total car");
self.totalCarsLabel.text = local;
local = NSLocalizedStringWithDefaultValue(@"CurrentNumber", nil, [NSBundle mainBundle], @"Current Car", @"Current car");
self.CarNumberLabel.text = local;
local = NSLocalizedStringWithDefaultValue(@"CarInfor", nil, [NSBundle mainBundle], @"CarInfor", @"CarInfor");
self.CarInfoLabel.text = local;
arrayOfCars = [[NSMutableArray alloc] init];//初始化汽车的数组为空数组
displayedCarIndex = 0;//显示创建的第一辆汽车
[self setupLandscapeConstraints];
UIInterfaceOrientation currOrientation = [[UIApplication sharedApplication]statusBarOrientation];
isShowingPortrait = UIInterfaceOrientationIsPortrait(currOrientation);
}
对齐问题偷了个懒,修改如图,如果有精力的话,可以按照第6、7节的方法去进行约束。记得会有一行放不下所有信息的情况,这时候要考虑换行的问题,这就交给你们自己去查咯
今天的介绍就到这里咯
我的另一个博客站点:Arnold-你们好啊