1.文本html
2.图片java
3.nibpython
4.其余资源git
1.APP图标github
2.应用名与权限提示shell
3.启动图(LaunchScreen)json
4.app调系统资源页面的国际化swift
5.涉及服务端数据内容的国际化数组
1.更改语言的方案xcode
2.未作国际化的旧项目迁移
国际化的本质是为每种语言单独提供一份资源(文本,图片,音视频等)。 本文术语 本地化:指单独一种语言 国际化:多种语言的合体
在工程的Localizations中每新增一种语言,xcode会提示咱们生成对应的文件,然后也生成了对应的文件夹。
iOS为这些文件提供了快捷的国际化方案。对于字符串资源文件生成相应语言的字符串文件放在对应的文件夹中,而XIB和StoryBoard则可选整个文件和字符串资源。具体的方案后续讨论。
若是忘了添加某个资源的具体语言文件,或者后续增长的资源文件,能够经过该资源文件的 文件监察器File Inspector
中的 Localize按钮添加。
Localizable.strings
和InfoPlist.strings
在国际化方案中是常见的。
NSLocalizedString
默认会加载的文件,若是自定了这个文件名字,则使用NSLocalizedStringFromTable
指定table便可info.plist
的字符串国际化文件,系统默认读取,名字固定添加了多语言的字符串资源文件处于可展开状态,子级有着相应语言的副本。咱们把相应语言的文本放在副本里面就好了。
字符串文件中具体的格式是"key" = "value";
笔者发现写成key = "value";
也是不会有问题的(可是不加双引号不能有空格,会识别不了),好比应用名称的本地化:
使用NSLocalizedString(key, comment)
来读取字符串。第二个参数comment能够是nil,能够是一段为空的字符串,也能够是对key的注释。
看一下这个方法的实现
#define NSLocalizedString(key, comment) \
[NSBundle.mainBundle localizedStringForKey:(key) value:@"" table:nil]
...
/* Method for retrieving localized strings. */
- (NSString *)localizedStringForKey:(NSString *)key value:(nullable NSString *)value table:(nullable NSString *)tableName NS_FORMAT_ARGUMENT(1);
复制代码
localizedStringForKey:value:table:
是NSBundle的对象方法,因而可知,能够加载不一样的包名和字符串资源表的字符串。也提供了相关宏
#define NSLocalizedStringFromTable(key, tbl, comment) \
[NSBundle.mainBundle localizedStringForKey:(key) value:@"" table:(tbl)]
#define NSLocalizedStringFromTableInBundle(key, tbl, bundle, comment) \
[bundle localizedStringForKey:(key) value:@"" table:(tbl)]
复制代码
重要:当找不到相应的语言strings或value时会直接返回key,若是你用英文的内容做为Key,甚至均可以不用维护英文本地化。
Xcode5以后图片资产(Assets.xcassets)再也不支持国际化了,单张图片资源的方式仍然可用,使用方式同字符串。将须要国际化的图片拖入工程,选择文件监察器,点击Localize并选择多个语言后便可生成如如字符串资源同样的可展开状态了。要配置不一样语言的图片前往该语言目录替换便可。
这个系统提供的方案支持Interface Builder
版的nib资源国际化(固然Localizable Strings 方式很显然只是字符串而已),也支持+ imageNamed:
加载方式的国际化。
还有个只适合用于纯代码,不支持nib的方式。就是把图片的名称作字符串国际化,而后再使用+ imageNamed:
加载。
另外,针对+imageWithContentsOfFile:
的加载方式,能够经过分类的方式,根据语言修改相应的加载路径。
PS:图片的国际化带来的是多份的副本,若是国际化中须要作的具体本地化语言较多,必然形成包的急剧增大。因此建议能避免就避免。
nib文件的国际化方式上面提到有两种方式:
nib文件有一个大坑,画重点
各个本地化的nib修改不会同步,nib的修改也不会同步至字符串资源
也就是说第一种方案每增长一种语言就得再画一个页面,本地化语言多的话,额外工做量惊人。 第二种方案,也得本身将新增的字符串拷贝出来。
若是要把更新同步的过程作成自动化,固然也是字符串方便一点。用整个nib文件作国际化比字符串资源方式强的地方也就是如下两点了
通常也不会去根据不一样本地化语言去修改布局,阿拉伯国家也就改个文本方向,这个特性视图自带,全局修改便可。
[UIView appearance].semanticContentAttribute = UISemanticContentAttributeForceRightToLeft;
复制代码
nib中的图片资源用代码也可轻松解决,综上笔者建议针对nib文件只作字符串资源(Localizable Strings)。
因此,上面的图片方案选了支持nib的方案,而后如今不用了 🤣 意不意外?惊不惊喜?
不说这个了,来讲说怎么作nib新增的须要国际化的字符串同步吧。
Xcode为咱们提供了ibtool
工具来生成nib的strings文件
ibtool FirstViewController.xib --generate-strings-file lanuchScreen.strings
ibtool Main.storyboard --generate-strings-file storyBoard.strings
复制代码
可是ibtool生成的strings文件是BaseStoryboard的strings(默认语言的strings),且会把咱们原来的(甚至是翻译好的)strings替换掉。仍是本身用脚原本作这个工做靠谱点,再借助Xcode 中 Run Script 来运行这段脚本,更新的时候build一下就好了。 具体的脚本代码在最后的Demo中,Run Script的添加方法: Target->Build Phases->New Run Script Phase,在shell里面写入下面指令
python ${SRCROOT}/${TARGET_NAME}/RunScript/AutoGenStrings.py ${SRCROOT}/${TARGET_NAME}
复制代码
其余资源(json、音视频、压缩包等等)的国际化方式与图片资源相同,读的时候读 主Bundle 便可,不一样语言环境下iOS自动切。
剧透:后续的应用内切换语言会利用主Bundle的这一特性。
这部份内容的国际化,可考虑如下两种方案:
第一种适合适配本地化语言较少的状况,好比只适配中英文;而第二种,对配置信息的依赖比较高,服务端须要修改的内容也是比较多的。
若是使用第一种方案,一些经常使用的报错信息或者其余业务成功等信息能够整理成特定的code
由客户端直接作解析,减小信息传输量(虽然相比单个本地化仍是会大不少)。
若是使用第二种方案,能够在请求头中带入当前用户的本地化信息,服务端根据这个判断,能够简便得多。
除了动态图标的方法, 暂时也查不到什么动态修改图标的方法了。这个方法多用于 APP的节日活动。 事实上也没人去作这个的国际化,顺带提一下。
应用名与权限提示的国际化就是依赖info.plist的国际化。不一样本地化文件放不一样的键值对便可。
Xcode Overview 的 Adding Assets章节中有关于启动图的描述
Because the launch screen is shown before your app is running, you can only use a single root view of type UIView or UIViewController.
也就是说启动界面的展现是发生在main函数入口以前,也就决定了咱们没法动态地修改启动图。另外,如下nib的两种国际化方式也是无效的。
这里要吐槽一下,即便作了静态国际化,如下两种情况是不会切换的
只有从新安装app的时候才会切换 因此作启动图的国际化意义有限。
也看到有人说本身作一个LaunchScreenController做为启动页,可是这个情况下,app启动会黑屏一段时间,这不是想要的效果啊。
关于调用系统资源,相机,相册,通信录之类,APP内修改语言暂没找到刷新的方法。若是你有方法,麻烦告知楼主,很是感谢。
只有在app重启时,main函数中应用程序代理(AppDelegate)返回以前去设置偏好设置的 AppleLanguages
才是有效的。
因此,目前的解决方案就是这些页面所有本身实现。另外,导航按钮的国际化文本也不是在 main bundle 中加载的,通常app也会自定义这个按钮,这个不是痛点。
若有其它,欢迎补充。
app的语言过年聚系统语言设置变化是最基本的国际化需求,更多的时候咱们但愿可以作到app内部热切换。
APP中的资源加载(Storyboard、图片、字符串)基本是在NSBundle.mainBundle()上操做的(自建私有库或者是三方库可能会本身作国际化,把国际化字符串资源放在本身的bundle中,如MJRefresh
),那么咱们只要在语言切换后把相应资源加载的bundle替换成当前语言的bundle就好了。以下替换为 字符串资源加载的主要代码:
id value = language ? [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:@"zh-Hans" ofType:@"lproj"]] : nil;
objc_setAssociatedObject([NSBundle mainBundle], &kBundleKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
……
- (NSString *)localizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName {
NSBundle *bundle = objc_getAssociatedObject(self, &kBundleKey);
if (bundle) {
return [bundle localizedStringForKey:key value:value table:tableName];
} else {
return [super localizedStringForKey:key value:value table:tableName];
}
}
复制代码
相应的nib文件中的图片加载和UITextView
中的文本也须要
若是,项目是纯代码的,也就是说国际化涉及不到nib文件,那就不须要这个实现方式了。本身存个当前语言标记,切换时换一个,作好判断便可。
若是想要在第一次安装的时候跟随系统的语言,应用启动后从NSUserDefault中能够读到语言数组,其中数组的第一个元素便是主要语言(Primary Language),系统的当前语言。 这些语言字符串当中的最后一部分是地区,会根据地区变化,后续根据这个列表判断的时候须要注意。
NSArray *array = [[NSUserDefaults standardUserDefaults] arrayForKey:@"AppleLanguages"];
复制代码
不论哪一种方式,切换语言都是须要刷新视图的,这个没法避免。 那么,如何优雅地刷新UI
这个思路有篇文章说的比较详细,直接看:在iOS App内优雅的动态切换语言
老项目的国际化迁移也都会牵涉到以上提到的各类问题。可是以上的问题都不是主要的,主要的是那些散落在代码中的各类须要国际化的文本。一个一个去抠出来确定不现实。 Xcode为咱们提供了一个工具genstrings
,这个工具与ibtool
相似,也是导出字符串资源文件的。只不过ibtool
适用于nib文件,而genstrings
适用于源代码文件。支持C,Objective-C,swift(官方未明确指出,笔者尝试经过),java等语言文件,以下官方描述:
The
genstrings
tool can parse C, Objective-C, and Java code files with the.c
,.m
, or.java
filename extensions.
然而,仍是有不少工做要作,看一下官方的来那个外一个描述:
If you wrote your code using the Core Foundation and Foundation macros, the simplest way to create your strings files is using the
genstrings
command-line tool. You can use this tool to generate a new set of strings files or update a set of existing files based on your source code.
也就是说,这个脚本生效的前提是必需要使用NSLocalizedString
系列宏,一个一个去替换字符串为这个宏的读取的这个工做仍是得本身作的。不过,想一想也是符合逻辑的,毕竟哪一个字符串要国际化仍是得开发者本身确认。经过Find navigator
本身作吧。
如何使用
//指定到en.lproj目录下的Localizable.strings文件,直接覆盖
genstrings -o en.lproj *.swift
//指定到en.lproj目录下的Localizable.strings文件,追加内容
genstrings -a -o en.lproj *.swift
复制代码
其余参数可使用man genstrings
命令查看,再也不赘述。 这个命令行工具一样有ibtool
的诟病,全量输出。因此,在使用的时候千万当心别覆盖了已经翻译的内容。
看下效果:
另外,这个命令一次只能解析一个文件,简单写了一个递归脚本:
#!/bin/bash
function getdir(){
for element in `ls $1`
do
dir_or_file=$1"/"$element
if [ -d $dir_or_file ]
then
getdir $dir_or_file
else
echo $dir_or_file
suffix="${dir_or_file##*.}"
if [ "$suffix"x = "swift"x ]||[ "$suffix"x = "m"x ]||[ "$suffix"x = "mm"x ];
then
genstrings -a -o en.lproj $dir_or_file
fi
fi
done
}
root_dir="./"
getdir $root_dir
复制代码
iOS国际化至此结束,若有哪里不清楚,欢迎查看demo,或者留言。 最后附上:demo地址
参考文章: Internationalization and Localization Guide Using the genstrings Tool to Create Strings Files iOS国际化——经过脚本使storyboard翻译自增 iOS国际化 在iOS App内优雅的动态切换语言
笔者和朋友作了淘宝优惠券公众号,购物领券省钱,帮忙关注一下。