乐趣区

iOS-International

原文链接
随着项目越来越成熟,逐渐拓展到海外市场,我们就需要适配多种国际化和地区、需要对自己的产品进行国际化,让更多的用户可以使用我们的 APP,这就需要对我们的产品进行国际化了。在这里就介绍一下自己在国际化项目里面踩过的一些坑。
Project 配置

打开你的工程,在左侧栏选中 project
在打开的面板中选中 project 下的蓝色图标
找到 Localizations 选项,添加你需要国家化的语言
在主工程下 command + N 新建 Localizable.string 文件
选中你创建的 string 文件,打开右侧面板
点击 Localization 组下的 Localize 按钮
把你刚才配置在工程内的选项添加进去就好。

调用方式

在以前调用的地方我们需要替换为本地化调用方式比如以前我们是这么调用的:
NSString *tips = @”wait”;

现在要换成
NSString *tips = NSLocalizedString(@”wait”, nil);
(ps 第二个是为了方便翻译人员理解上下文语境使用的。)
然后在 stirng 文件内添加对应的字符串:
“wait” = “ 别着急 ”;
你可以在不同的文件添加对应不同语言的翻译。
让我们看下这个宏的定义:
#define NSLocalizedString(key, comment) \
[NSBundle.mainBundle localizedStringForKey:(key) value:@”” table:nil]
#define NSLocalizedStringFromTable(key, tbl, comment) \
[NSBundle.mainBundle localizedStringForKey:(key) value:@”” table:(tbl)]
#define NSLocalizedStringFromTableInBundle(key, tbl, bundle, comment) \
[bundle localizedStringForKey:(key) value:@”” table:(tbl)]
#define NSLocalizedStringWithDefaultValue(key, tbl, bundle, val, comment) \
[bundle localizedStringForKey:(key) value:(val) table:(tbl)]

可以看到实际上就是从 mainBundle 中取出了指定的 String 文件,然后根据我们在代码中定义的‘key’值取出 value
有的时候我们要指定我们的 string 文件名字而不使用上面的那个默认名字。
NSString *tips = NSLocalizedStringFromTableInBundle(@”wait”, @”TDFOSLocalizable”, [NSBundle bundleForClass:[self class]], @”some tips to tell user wait”);
这里面多出来两个参数, 第一个是我们要指定的 string 文件名字, 第二个就是要从哪个 bundle 中取, 这个 bundle 的问题我们下面就会讲到。
使用脚本替换工程内部调用方式

那么在我们工程很大的情况下我们要把全部的字符串都替换为前缀为 NSLocalizedString 的形式人工手动替换肯定是不行的, 又慢又不安全, 没准复制粘贴的时候还把原来的 key 改错了, 这里贴一段 python 的实例代码, 可以稍加改动运行替换工程中的 string 前缀。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import re
import sys
import datetime

folderPath = ‘/Users/felix/Documents/2dfire/TDFOpenShop/TDFOpenShop/Classes’
stringToReplace = ‘NSLocalizedString’
stringReplaceTo = ‘TDFOSLocalizedString’

def scan_files(rootdir):
files = []
for parent, dirnames, filenames in os.walk(rootdir):
for filename in filenames:
if len(filename.split(‘.’,1))>1:
if filename.split(‘.’,1)[1] == ‘m’:
files.append(os.path.join(parent, filename))
return files

def replaceStringIn(file):
code = open(file,’r+’)
text = code.read()
code.seek(0,0)
code.write(text.replace(stringToReplace,stringReplaceTo))
code.close()

def main():
files = scan_files(folderPath)
for filePath in files:
replaceStringIn(filePath)

if __name__ == ‘__main__’:
main()
这里面我是把以前的 NS 开头的宏替换为自定义的宏,大同小异,可以参照这个修改下即可。
编译运行测试

当我们全部修改好以后肯定是要测试下显示对不对的、有两种方法可以快速切换 App 语言

打开模拟器或真机 general -> setting -> lang , 不过这样比较繁琐。
点击导航栏上的模拟器图标左边的 schema 选项, 选择 editSchema -> Run -> Options ->Application Language 直接改为你需要验证的语言运行就可以啦。

如何在模块内单独配置国际化文件

很多时候我们的工程体量大到一定程度的时候都会模块化掉, 几个人或者一个人负责一个模块, 而有的模块是要作为 SDK 提供外部 interface 使用的。当你把 SDK 提供出去的时候, 我们期望的效果是在其他人(其他工程)内部运行的、我们的 SDK 也能够国际化显示。但是在我们整个工程的 string 文件包含几千上万条的时候显然不需要全部移动到模块内。
所以在这里面我们要做的就是把需要的使用到的字符串和翻译好的 value 从主工程迁移到模块内部。
解决方案:使用 cocoapods 集成的模块化内部进行国际化
我们先把主工程的国际化文件的文件夹复制到我们的模块路径下面, 在模块内部有一个配置文件 x.podspec 里面添加这样一段配置
s.resources = ‘xxx/*.{xib,jpg,png,xcassets}’,’xxx/*.lproj’
主要注意后面 , 这里就把我们刚复制来的国际化问价加入了模块的资源中,这时,如果我们不想用跟主工程一样的名字,Localizable.strings,可以把这个名字也给改掉,比如 abc.strings
调用
这里为了有别于主工程的国际化,我们把 strings 文件改名为 abc.strings 然后在模块内新建一个头文件
#ifndef TDFOSLocalizeMacro_h
#define TDFOSLocalizeMacro_h

#define TDFOSLocalizedString(key, comment) \
NSLocalizedStringFromTableInBundle(key, @”abc”, [NSBundle bundleForClass:[self class]], comment)

#endif /* TDFOSLocalizeMacro_h */
这里可以使用上面的脚本再次替换字符串前缀, 然后运行下看看是否替换成功。这里注意要重新 pod install 下, 否则 cocoapods 不会帮我们把资源引入包内。ps: 别忘了删掉主工程中移除来的字符串!!!
总结
基本用法暂时介绍到这里,关于模块化和国际化的东西要多了解一下 NSbundle 这个类。

退出移动版