App语言国际化,也叫语言本地化,根据用户使用的操作系统的语言设置,自动将App的语言设置成和用户使用的操作系统的语言一致的语言。
本文将分如下7个主要章节一步一步讲解如何完全本地化一个App。
- 配置需要国际化的语言(国际化的准备工作)
- App名称本地化
- 代码中字符串本地化
- 多人开发情况下的字符串本地化
- 图片本地化(两种方式两种方式)
- 查看/切换本地语言
- storyboard/xib本地化
一、配置需要国际化的语言
首先,根据具体需求来配置需要使用到的国际化的语言,国际语言种类很多,没有必要全部都加上,根据实际需求选择性添加几种需要用到的语言即可。不管我们是国际化App的名称、界面中的字符串文字信息,还是图片、图标,都需要先进行配置准备工作,具体步骤如下所示:
1、打开项目工程,找到选中PROJECT-->Info-->Localizations,然后点击“+”,然后添加需要国际化/本地化的语言,(默认需要勾选下面的“Use Base Internationalization”);
2、这里以添加德语为例,点击加好之后,找到德语选项,然后弹出一个对话框,直接点击“Finish”即可,同理,其他需要添加的语言也是按照这种操作步骤进行;
二、App名称的国际化/本地化设置
1、选中Info.plist,然后使用快捷键command + n,新建文件,然后选择Strings File类型的文件(iOS-->Resource-->Strings File);
2、文件名字必须要命名为首字母大写的“InfoPlist”,就算是首字母小写也不行,如果不按照这个名字来,你绝对设置不成功的!然后文件名后面在创建成功之后会自动生成后缀,这里不用担心,只要把文件名字写对就行了;
3、点击create之后,xcode左侧导航列表里就会新出现一个名为InfoPlist.strings的文件,然后选中这个文件名,在xcode的File inspection点击Localize,这样做是为了选择需要的本地化语言;
4、点击Localize之后,会弹出一个提示对话框,展开对话框列表,发现下拉列表所展示的所有语言就是我们需要国际化的语言,选择需要本地化的语言,然后点击对话框的Localize按钮,然后依次把需要的语言都按照这种方法选中添加即可;
5、然后在添加完的国际化语言列表里面全部勾选刚才添加的国际化语言列表,然后再回去Xcode左侧的InfoPlist.strings的文件下面多了子文件,然后点击箭头展开,会发现添加的几个国际化语言文件;
6、然后在InfoPlist.strings下面所有的国际化语言文件里面分别添加对应的App名字,比如英语类型里面,就写:CFBundleDisplayName = "English"; //English就是App英文的名字;
7、依次在剩下的几种语言里面分别添加对应的App本地化名字即可。具体图解步骤如下所示:
三、项目详情中字符串的本地化处理
字符串本地化处理,就是App里面的字符串在不同的语言下显示对应语言的内容,eg:"我的"这个词语在简体中文语言环境下就显示“我的”,在英语环境下就显示“Me"。其实字符串本地化和App名称本地化的过程一模一样,只不过创建的文件名字不一样罢了,这里的字符串本地化创建的文件名字必须是:Localizable,错一个字母都不行,首字母小写也不行,不然就不会成功本地化处理。
1、与App名称本地化创建文件的步骤一样,使用快捷键command + n,新建文件,然后选择Strings File类型的文件(iOS-->Resource-->Strings File);
2、文件名必须命名为Localizable,文件创建成功之后,查看xcode左侧多出来一个名为Localizable.strings的文件,然后选中该文件,在xcode的File inspection点击Localize;
3、点击Localize之后,会弹出一个提示对话框,展开对话框列表,发现下拉列表所展示的所有语言就是我们需要国际化的语言,选择需要本地化的语言,然后点击对话框的Localize按钮,然后依次把需要的语言都按照这种方法选中添加即可;
4、然后在添加完的国际化语言列表里面全部勾选刚才添加的国际化语言列表,然后再回去Xcode左侧的Localizable.strings的文件下面多了子文件,然后点击箭头展开,会发现添加的几个国际化语言文件;
5、然后在Localizable.strings下面所有的国际化语言文件里面,分别以键值对的形式在代码中给每一个需要本地化的字符串赋值,比如英语里面:"home" = "Home",那么简体中文里面:"home" = "主页" ,依次在每个对应的语言文件里面添加该键值对对应的值;
6、为了方便起见,直接使用Foundation框架系统自带的宏来根据Key获取对应的字符串,然后赋值给代码中字符串,这个宏是:#define NSLocalizedString(key, comment) [[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:nil]
7、具体在代码里调用:
NSString *cart = NSLocalizedString(@"cart", nil);
self.title = cart;
这里就不再发全部截图,以上步骤截图可以参照App名字本地化的那些步骤来就行,下面只发一下不一样部分的截图:
四、图片设置本地化配置
图片设置本地化和Localizable.strings类似,图片资源存放在Images.xcassets里,使用时将不同语言的图片资源在Localizable.strings里一一对应设置,如下所示:
Localizable.strings (English)
"imageName" = "pic-e";
Localizable.strings (Chinese(Simplified))
"imageName" = "pic-c";
方式二
首先需要添加需要本地化的语言,具体步骤参考第一章配置需要国际化的语言。因为我演示的demo中在本地化App名称时已经添加了需要国际化的语言。所以不需要再设置。
将图片拖入工程中,例如“icon.png”,然后选中icon.png,展开Xcode右侧的file Inspection,点击Localize,如下图:
然后,右击icon.png->show in Finder,我们发现在en.Iproj文件中多了一个名为icon.png的图片,如下图:
当然,zh-Hans.Iproj文件夹下并没有图片,如下图:
我们只需给zh-Hans.Iproj添加一个名字也为icon.png的图片。如下图:
然后把zh-Hans.Iproj中的icon.png拖到Xcode中,如下图:
然后控制器中添加如下代码:
#import "ViewController.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSString *imageName = NSLocalizedString(@"icon", nil);
UIImage *image = [UIImage imageNamed:imageName];
self.imageView.image = image;
}
@end
五、货币值设置本地化配置
货币显示在不同的国家是有区别的,例如:100000可以写作"100,000"也能写作"100.000"。针对这种情况可以使用NSNumberFormatter格式化,例如:
NSNumberFormatter *numberFor = [[NSNumberFormatter alloc] init];
[numberFor setNumberStyle:NSNumberFormatterDecimalStyle];
NSString *numberString = [numberFor stringFromNumber:@(100000)];
testLabel.text = [NSString stringWithFormat:NSLocalizedString(@"testNum:%@", nil), numberString];
六、Xcode 8 权限提示语国际化/本地化配置
配置权限国际化和配置应用程序名字国际化一样,具体Key值如下:
NSMicrophoneUsageDescription 麦克风权限
NSCameraUsageDescription 相机权限
NSPhotoLibraryUsageDescription 相册权限
NSBluetoothPeripheralUsageDescription 蓝牙权限
NSSpeechRecognitionUsageDescription 语音转文字权限
NSCalendarsUsageDescription 日历权限
NSLocationWhenInUseUsageDescription 定位权限
NSLocationAlwaysUsageDescription 定位权限
七、 多人开发情况下的字符串本地化
项目开发中,独立开发的还是少数。经常会有多人开发的情况,这种情况,如果多人同时操作本地化文件,极有可能会存在冲突。另一方面,我们又不希望自己的本地化文件受到对方的污染,也就是说,我们不希望对方操作我们的本地化文件。但是上面介绍的代码中字符串的本地化是使用的是默认的文件名"Localizable",因为启动程序时,系统将根据语言加载相应的文件得到其对应的字符串文件,这个字符串可以通过系统将NSLocalizedString中的宏生成名为“Localizable.strings”的文件。那么如何让系统加载我们自己命名的本地化文件而非系统默认的Localizable.strings呢?这就是 NSLocalizedStringFromTable(<#key#>, <#tbl#>, <#comment#>)的用处。
也就是说,如果你的strings文件名字不是Localizable而是自定义的话,如VVS.strings,那么你就得使用NSLocalizedStringFromTable这个宏来读取本地化字符串。
// key:系统根据key取字符串
// tbl:自定义strings文件的名字
// comment:可以不传
NSLocalizedStringFromTable(, , )
#import "ViewController.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIButton *btn;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *title = NSLocalizedStringFromTable(@"click", @"VVS", nil);
[self.btn setTitle:title forState:UIControlStateNormal];
}
@end
运行效果,如下图:
如此一来,我们就可以挣脱别人的strings文件和系统默认的Localizable.strings文件,自己另起炉灶。
八、查看/切换本地语言
原理:应用启动时,首先会读取NSUserDefaults中的key为AppleLanguages对应的value,该value是一个String数组,也就是说,我们访问这个名为AppleLanguages的key可以返回一个string数组,该数组存储着APP支持的语言列表,数组的第一项为APP当前默认的语言。
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *languages = [[NSUserDefaults standardUserDefaults] valueForKey:@"AppleLanguages"];
NSString *currentLanguage = languages.firstObject;
NSLog(@"模拟器当前语言:%@",currentLanguage);
}
@end
同理,既然我们可以通过AppleLanguages这个key从NSUserDefaults中取出语言数组,那么我们也可以给AppleLanguages这个key赋值来达到切换本地语言的效果,从此以后,我们就无需频繁的去模拟器的设置->通用->语言与地区 中切换语言。
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 切换语言前
NSArray *langArr1 = [[NSUserDefaults standardUserDefaults] valueForKey:@"AppleLanguages"];
NSString *language1 = langArr1.firstObject;
NSLog(@"模拟器语言切换之前:%@",language1);
// 切换语言
NSArray *lans = @[@"en"];
[[NSUserDefaults standardUserDefaults] setObject:lans forKey:@"AppleLanguages"];
// 切换语言后
NSArray *langArr2 = [[NSUserDefaults standardUserDefaults] valueForKey:@"AppleLanguages"];
NSString *language2 = langArr2.firstObject;
NSLog(@"模拟器语言切换之后:%@",language2);
}
@end