所在团队:伴鱼国际化团队
前言
为了解决国际化语言翻译的问题,以及以后各个业务语言文件相互独立防止引用其他业务无用字段,设计了这款多语言组件方案
ios默认的多语言实现方案Localizable.strings
1: 原生多语言使用方式
苹果系统为了支持多语言而给开发者创建了一套多语言的方案就是Localizable.strings的方式如图所示
然后在设置的对应国家中设置@"key" = @"value"; 这种格式就可以正常使用了例如如果是一个确认的文案,在做多语言适配的时候可以在对应语种下设置键值对.
| 语种 | 键值对应 |
|---|---|
| Localizable.strings (English) | @"common_Next" = @"Next"; |
| Localizable.strings (Chinese, Simplified) | @"common_Next" = @"下一步"; |
| Localizable.strings (Japanese) | @"common_Next" = @"次のステップ" |
在使用时候直接调用系统方法 NSLocalizedString(@"common_Next", nil); 正常使用就可以了.
2:苹果系统多语言问题
1 字段数量: 如果一个项目比较完善.那么每个.strings里有非常多的字段,成千上万行都是有可能的,无用字段不容易删除,新添加字段需要去重搜索,而且容易出现疏忽导致某个语言下翻译失败.
2 更新问题: 每次更新字段都需要打包重新提交审核
3 通用性问题: 如果公司下面有5个产品,那么字段无法直接公用,多人开发时候也容易导致某些key重复添加
这3点是遇到的比较麻烦的问题.下面我会通过介绍我们开发的组件去讲解是如何解决这几个问题的.
PFLocailzed基本介绍
PFLocailzed是开发出来用来支持多语言的组件,主要支持,在线更新,本地阅读,从服务端下载多语言文件方便更新适配.
2.1 结构介绍
PFLocalied:核心类,包含初始化方法和通过方法,以及获取值的方法
PFLocalizedProvider:是一个代理协议,让外部具体业务去实例化遵守协议的对象来设置例如存放位置,初始化,服务端路径等相关业务代码
PFLocalizedContent: 缓存存储的网络文件和本地文件,以及远端更新的具体实现,通过缓存的key来先从缓存读取如果没有缓存,在读具体文件并刷新缓存
PFLocalizedCacheManager 具体的缓存代码
PFLocalizedFetch 具体的网络请求及相关数据处理的方法
PFLocalizedSetting 对于更新的一些配置,现在是远端刷新的时间配置
2.2 流程图
业务方
1.业务方初始化locilazed
[PFLocalized initializeLocalized:PFLocalizedClassProvider.new];
PFLocalized *localized = [PFLocalized localized];
NSBundle *bundle = [NSBundle bundleForClass:PFLocalizedClassModule.class];
NSString *path = [bundle pathForResource:@"PCLocalizedEntity" ofType:@"bundle"];
bundle = [NSBundle bundleWithPath:path];
if (bundle == nil) {
bundle = [NSBundle mainBundle];
}
path = [bundle pathForResource:@"LocalizedDefault" ofType:@"bundle"];
NSString *fileName = localized.languageCode;
path = [path stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.json",fileName]];
[localized setDefaultsFromJsonFilePath:path];
2.创建遵守PFLocalizedProvider协议的类并实现配置方法
自定义网络请求
- (void)fetchRemoteCompletionHandler:(nullable void (^)(NSDictionary * _Nullable, NSError * _Nullable))completionHandler { {
NSString *url = @"https://int.picturebook.ipalfish.com/pfapi/ugc/config/language/text/get";
[[HttpClient sharedClient] post:url param:@{} successBlock:^(id data) {
completionHandler?completionHandler(data,nil):nil;
} failureBlock:^(NSError *error) {
completionHandler?completionHandler(nil,error.toNSError):nil;
}];
}
自定义解析
- (NSDictionary *)transformResponse:(NSDictionary *)response {
return response[@"ent"][@"language_texts"];
}
解析语种
- (NSString *)transformLanguageCodeOfOrigin:(NSString *)origin {
NSString *result = @"en";
if (origin == nil) {
return result;
}
NSString *lowerLc = origin.lowercaseString;
if ([lowerLc hasPrefix:@"zh"] || [lowerLc hasPrefix:@"yue"]) {
if ([lowerLc hasSuffix:@"tw"] ||
[lowerLc hasSuffix:@"hk"] ||
[lowerLc hasSuffix:@"mo"] ||
[lowerLc containsString:@"hant"]) {
result = @"zh-HK";
} else {
result = @"zh-CN";
}
} else if ([lowerLc containsString:@"en"]) {
result = @"en"; //英文
} else if ([lowerLc containsString:@"vi"]) {
result = @"vi"; //越南
} else if ([lowerLc containsString:@"jp"] || [lowerLc containsString:@"ja"]) {
result = @"ja"; // 日语
} else if ([lowerLc containsString:@"th"]) {
result = @"th"; //泰语
}
return result;
}
设置刷新时间
#if DEBUG
return 10;
#endif
return 43200;
}
3.导入对应本地文件放入项目中
组件
1.程序启动后,读取本地文件并且同步到内存中
2.请求远端存储并判断是否超过业务方设置的时间间隔
3.未超出则直接结束,如果超出则根据业务的配置请求远端数据
4.解析远端数据并且更新到本地存储中
5.读取本地的远端存储数据同步到内存中,
问题解决方案
1.字段数量问题可以通过类型腾讯云的文档形式在多人开发的时候共同维护一篇文档,如果需要的字段文档中存在则可以直接使用,如果不存在则补充进去
2.更新问题:在测试前可以本地导入对应文档或者直接让服务端定时读取腾讯云的文档进行下发,不需要每次处理,如果上线出现问题也可以直接更新文档来解决
3.通用性问题,如果其他app使用则可以复制通用字段即可(我们团队的定义是通用字段已com_为开头,其他app想要使用只需要开启新文档并且只导入com_开头的字段即可)
总结:
采用上述方案可以很好的解决苹果原生多语言的更新问题和通用性问题,方便团队多人开发.导致的字段重复以及引入无用字段的问题.更新字段的方式也可以让开发人员节省多语言适配的时间.只需要在文档中填充字段的key,让翻译去补充对应的值服务端及时更新就可以.希望能对大家产生帮助