一、国际化步骤
- 添加相关语言
- 创建Localizable.strings、InfoPlist.strings文件
- 写入需要国际化的键值对
- 通过NSLocalizedString(@"", nil) 调用
二、问题
在实现的过程中遇到的问题:
- 项目已写好,怎么获取需要国际化的内容
- 获取到国际化的内容怎么一键写入文件
- 当有多国语言时,怎么根据Excel提供的翻译快速录入
关于问题1、2 可以通过脚本或shell命令来查找,由于我当时使用的是shell命令,就只讲这一点
find ./ -name "*.m" -print0 | xargs -0 genstrings -o en.lproj
这个命令有个缺点:只能识别被NSLocalizedString(@"国际化", nil) 包裹的内容,如这里的"国际化",且需提前cd到'en.lproj'同级目录下
三、主菜
接下来就聊聊本次的主要内容,如何自动化写入多国语言
前提条件
- Localizable.strings里基础语言已准备完毕
- 工具类:CHCSVParser
- Excel翻译文件,如下这种:
Localizable.strings
这个文件可以通过字典的方式读取:
//读取基础语言键值对
NSDictionary * dic = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"source" ofType:@"strings"]];
//获取所有key
_keyArr = dic.allKeys;
获取基础语言所有key,是为了后续写入其他语言时作为依据;因为产品提供的Excel翻译包含的是iOS和Android中的,可能存在有些翻译未使用的情况,所以我们以自己的基础语言为准
CHCSVParser
这是找的一个工具类,用来读取excel.csv文件,将普通的Excel文件另存为以UTF8编码的excel.csv文件即可
//excel.csv文件路径
NSString *filePath = [[NSBundle mainBundle] pathForResource:fileName ofType:(fileName.pathExtension.length > 0) ? nil : @"csv"];
//初始化
CHCSVParser *parse = [[CHCSVParser alloc] initWithContentsOfCSVURL:[NSURL fileURLWithPath:filePath]];
parse.delegate = self;
CHCSVParserDelegate 代理如下:
// 开始读取文件
- (void)parserDidBeginDocument:(CHCSVParser *)parser
// 文件读取失败
- (void)parser:(CHCSVParser *)parser didFailWithError:(NSError *)error
// 读取到一行的某一列,field:内容,fieldIndex:列下标(从0开始)
- (void)parser:(CHCSVParser *)parser didReadField:(NSString *)field atIndex:(NSInteger)fieldIndex
// 文件读取完毕
- (void)parserDidEndDocument:(CHCSVParser *)parser
// 开始读取某一行
- (void)parser:(CHCSVParser *)parser didBeginLine:(NSUInteger)recordNumber
至此,我们已能够完成两件事:
- 基础语言的读取
- Excel文件的读取
在parser:didReadField:atIndex: 代理中,可以对文件内容进行特异化处理后进行保存
- (voi*)parser:(CHCSVParser *)parser didReadField:(NSString *)field atIndex:(NSInteger)fieldIndex {
if (fieldIndex >= _paeseResults.count) {
//超出语言个数的部分不处理
return;
}
field = [self removeInvalidStr:field];
//如果有等号 取等号前面的
field = [field componentsSeparatedByString:@"="].firstObject;
if ([field containsString:@"\""]) {
//如果字符串包含引号,添加\,以保证写入时有转义符
field = [field stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""];
}
[_paeseResults[fieldIndex] addObject:field];
}
- (NSString *)removeInvalidStr:(NSString *)sourceStr
{
NSMutableString *aLanguage = [[NSMutableString alloc] initWithString:sourceStr];
if ([aLanguage containsString:@","] && [aLanguage hasPrefix:@"\""] && [aLanguage hasSuffix:@"\""]) {
[aLanguage replaceCharactersInRange:NSMakeRange(0, 1) withString:@""];
[aLanguage deleteCharactersInRange:NSMakeRange(aLanguage.length-1, 1)];
}
return [aLanguage copy];
}
在parserDidEndDocument: 代理中进行文件写入:
/*
这里我们以英语为基础语言,
中文为注释,法语、西班牙语为需要自动化写入的语言
_paeseResults:二级数组,每个数组元素包含的是每一列的数据
*/
// 第一列:你好、名字,属于注释部分
NSArray * notes = _paeseResults[0];
// 第二列:Hello、Name,为Excel包含的所有英语
NSArray * keyArr = _paeseResults[1];
// _keys为基础语言(英语)文件读出的所有key
for (int i = 2; i < _paeseResults.count; i++) {
NSArray * array = _paeseResults[i];
NSMutableString * content = [NSMutableString string];
for (int j = 0; j < _keys.count; j++) {
NSString * key = _keys[j];
if ([key containsString:@"\""]) {
//基础语言的key可能包含引号,添加转义符
key = [key stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""];
}
//注释
NSString * note;
//写入的值:翻译
NSString * value;
if ([keyArr containsObject:key]) {
NSInteger index = [keyArr indexOfObject:key];
note = [NSString stringWithFormat:@"/* %@. */",notes[index]];
value = array[index];
} else {
note = @"/* No comment provided by engineer. */";
value = @"";
}
[content appendString:@"\n"];
[content appendString:note];
[content appendString:@"\n"];
[content appendFormat:@"\"%@\"",key];
[content appendString:@" = "];
[content appendFormat:@"\"%@\"",value];
[content appendString:@"\n"];
}
[self writeContent:content index:i];
}
- (void)writeContent:(NSString *)content index:(int)index {
NSArray * paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString * fileName = [NSString stringWithFormat:@"local_%d.strings",index];
NSString * filePath = [documentsDirectory stringByAppendingPathComponent:fileName];
BOOL isDir;
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:filePath isDirectory:&isDir]) {
[fileManager createFileAtPath:filePath contents:nil attributes:nil];
}
[content writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
}
结果如下:
至此,基本生成完毕,没有找到翻译的key:写入空值,方便搜索排查 缺点:由于基础语言文件是用字典读取的,获取的key没有顺序,最后写入文件的顺序与基础语言排版顺序不一致,如果基础语言是按字母顺序排序的话,写入前可以先对_keys排序
都看到这里了给作者个赞鼓励下呀