app swift 内语言切换

2017-06-30 10:04:16 aa654403231 阅读数 2152

重点是app 内部切换

1.配置languege.strings.infoPist.Strings












2.LocalizationTool.swift,实现内部切换

//
//  LocalizationTool.swift
//  IFXY
//
//  Created by LiuXing on 2017/3/7.
//  Copyright © 2017年 IFly. All rights reserved.
//

import UIKit

class LocalizationTool: NSObject {
     static let shareInstance = LocalizationTool()

     let def = UserDefaults.standard
     var bundle : Bundle?
     
     func valueWithKey(key: String!) -> String {
          let bundle = LocalizationTool.shareInstance.bundle
          let str = bundle?.localizedString(forKey: key, value: nil, table: "Language")
          return str!
     }
//    class func valueWithKey(key: String!) -> String {
//        
//        let languageString = SynthesizerSettingTool.shareIntance.vocieParams?.languageType
//        let path = Bundle.main.path(forResource: languageString!, ofType: "lproj")
//        let value = (Bundle.init(path: path!)?.localizedString(forKey: key, value: nil, table: "Language"))!
//        return value
//    }
     
     func setLanguage(langeuage:String) {
          var str=langeuage
          if langeuage=="" || langeuage==nil{
               
               let languages:[String]=UserDefaults.standard.object(forKey: "AppleLanguages") as! [String]
               let str2:String=languages[0]
               if ((str2=="zh-Hans-CN")||(str2=="zh-Hans")){
                    str="zh-Hans"
               }else{
                    str="en"
               }
               
          }
          UserDefaults.standard.set(str, forKey: "langeuage")
          UserDefaults.standard.synchronize()
          let path = Bundle.main.path(forResource:str , ofType: "lproj")
          bundle = Bundle(path: path!)
//          def.set(langeuage, forKey: UserLanguage)
//          def.synchronize()
          NotificationCenter.default.post(name: NSNotification.Name(rawValue: "LanguageChanged"), object: nil)

          
     }
}

3.在appdelegate里面     

       var languege:String=""
//        guard languege==UserDefaults.standard.value(forKey: "langeuage") as! String else{
//               languege=""
//        }
        if  (UserDefaults.standard.value(forKey: "langeuage")) != nil {
            languege=UserDefaults.standard.value(forKey: "langeuage") as! String
        }
        LocalizationTool.shareInstance.setLanguage(langeuage: languege)

4.语言切换界面



  func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        
        tableView.deselectRow(at: indexPath, animated: false)
        selectCol = indexPath.row
        tableView.reloadData()
        if   indexPath.row == 0 { 
 
          LocalizationTool.shareInstance.setLanguage(langeuage: "zh-Hans")
        }  else { 
 
          LocalizationTool.shareInstance.setLanguage(langeuage: "en")
        }
     

    
    }
点击切换语言之后,需要立即修改之前缓存的页面

 

        NotificationCenter.default.addObserver(self, selector: #selector(changeLanguage), name: NSNotification.Name(rawValue: "LanguageChanged"), object: nil)

页面所有的viewdidload方法里面加上监听

 

 func changeLanguage(){
           items = [["title": LocalizationTool.shareInstance.valueWithKey(key: "my_language_zh")],["title": LocalizationTool.shareInstance.valueWithKey(key: "trans_title_en")]]
          self.title = LocalizationTool.shareInstance.valueWithKey(key: "my_language_switch")//"切换语言"
          
          if (UserDefaults.standard.value(forKey: "langeuage") as! String) == "en"{ // 英语
               selectCol = 1
          } else {
               selectCol = 0
          }
          m_TableView.reloadData()
    }

tip:日期选择器

fileprivate lazy var datePicker:UIDatePicker = {[unowned self] in
        let datePic = UIDatePicker()
        datePic.backgroundColor = UIColor.white
     let languege=UserDefaults.standard.value(forKey: "langeuage") as! String
     var sexstr=UserAccountTool.shareIntance.account?.sex
     if languege=="en" {
          datePic.locale = Locale(identifier: "en")

 }else{
        datePic.locale = Locale(identifier: "zh_CN")  
     }
//        datePic.locale = Locale(identifier: "zh_CN")
        return datePic
        
    }()


2018-03-12 23:36:00 weixin_30724853 阅读数 25

最近一个一直在迭代的老项目收到一份新的开发需求,项目需要做国际化适配,简体中文+英文。由于项目中采用了storyboard和纯代码两种布局方式,所以国际化也要同时实现。上网查了些资料,实现了更改系统语言后,修改app内语言的问题。具体国际化方式可以参考下文:

3分钟实现iOS语言本地化/国际化

这篇文章讲的比较详细,很容易实现。

这个需求实现后不久,产品又给我提了一个需求,让我要在app内实现语言切换。还好之前的国际化也做了些准备,不慌不慌。

接下来就是方案的选定,通过广泛查阅资料,得出两个备选方案:

方案一:在原国际化版本的基础上做修改,在info.plist文件中新增key="appLanguage"的键值对,保存用户设定的语言类别。通过切换语言类别来改变语言。(例子:微信)

优点:之前有国际化操作的基础,执行起来并不复杂。

缺点:切换完语言后,需要重新创建app keywindow的跟控制器,会有个跳转的过程,用户体验不好。

方案二:切换语言后,发送通知,每个控制器收到通知后,更改语言。(例子:新浪微博)

优点:很自然的切换语言,选择语言后即可切换,不需要重置根控制器,用户体验好。

缺点:每个控制器都得注册接收通知,工作量太大,而且storyboard也得单独处理。

综合两个方案的优缺点,我们选择方案一。

中英切换,就是让App根据自身设置的语言去读取对应的国际化文件。在NSUserDefault中有一个字段:"AppleLanguages",这个字段就是负责存储App语言的字段,默认这个字段会根据系统语言去变动,中文系统他就存储中文,英文系统就存储英文。

废话少说,切换语言的过程上代:

// NTVLocalized.h

#import <Foundation/Foundation.h>

static NSString * const AppLanguage = @"appLanguage";

@interface NTVLocalized : NSObject
+ (NTVLocalized *)sharedInstance;

//初始化多语言功能
- (void)initLanguage;

//当前语言
- (NSString *)currentLanguage;

//设置要转换的语言
- (void)setLanguage:(NSString *)language;

//设置为系统语言
- (void)systemLanguage;

@end

 

// NTVLocalized.m

#import "NTVLocalized.h"

@implementation NTVLocalized
+ (NTVLocalized *)sharedInstance {
    static NTVLocalized *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[NTVLocalized alloc] init];
    });
    return instance;
}

- (void)initLanguage{
    NSString *language=[self currentLanguage];
    if (language.length>0) {
        NSLog(@"自设置语言:%@",language);
    }else{
        [self systemLanguage];
    }
}

- (NSString *)currentLanguage{
    NSString *language=[[NSUserDefaults standardUserDefaults]objectForKey:AppLanguage];
    return language;
}

- (void)setLanguage:(NSString *)language{
    [[NSUserDefaults standardUserDefaults] setObject:language forKey:AppLanguage];
}

- (void)systemLanguage{
    NSString *languageCode = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleLanguages"][0];
    NSLog(@"系统语言:%@",languageCode);
    if([languageCode hasPrefix:@"zh-Hans"]){
        languageCode = @"zh-Hans";//简体中文
    }else if([languageCode hasPrefix:@"en"]){
        languageCode = @"en";//英语
    }
    [self setLanguage:languageCode];
}

@end

当语言设置完成后,需要重新设置keywindow的rootViewController才可以实现语言的切换。
然而这样设置后,我们发现只有NSLocalizedString(key, comment)设置的语言才能正常显示我们需要的语言,storyBoard和xib配置的页面语言不跟着切换。
设置AppleLanguages字段的话,只会在下次启动App才会生效,在App启动后就已经生成了一个Bundle,里面识别好了对应着AppleLanguages的国际化文件,在App运行期间设置这个字段,是不生效的,所以我们去修改这个Bundle,写一个NSBundle的扩展。

// NSBundle+language.h

#import <Foundation/Foundation.h>

@interface NSBundle (language)
// 设置语言
+ (void)setLanguage:(NSString *)language;
@end

 

// NSBundle+language.m

#import "NSBundle+language.h"
#import <objc/runtime.h>

static const char _bundle = 0;

@interface BundleEx : NSBundle

@end

@implementation BundleEx

- (NSString *)localizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName {
    NSBundle *bundle = objc_getAssociatedObject(self, &_bundle);
    return bundle ? [bundle localizedStringForKey:key value:value table:tableName] : [super localizedStringForKey:key value:value table:tableName];
}

@end

@implementation NSBundle (Language)

+ (void)setLanguage:(NSString *)language {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        object_setClass([NSBundle mainBundle], [BundleEx class]);
    });
    
    objc_setAssociatedObject([NSBundle mainBundle], &_bundle, language ? [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:language ofType:@"lproj"]] : nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

@end

重新写一下设置语言的方法:

- (void)setLanguage:(NSString *)language{
    [NSBundle setLanguage:language];
    [[NSUserDefaults standardUserDefaults] setObject:language forKey:AppLanguage];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

综上所述,只是修改appleLanguage,在不重启应用的情况下,不能修改语言。所以我们选择修改bundle的方法。
代码在github上可以下载到:
https://github.com/FrankiezZZ/NTVLocalized

欢迎各位小伙伴加入iOS交流群:140147825

转载于:https://www.cnblogs.com/FrankieZ/p/8552830.html

2018-04-27 09:09:44 qq_40201300 阅读数 626

前言

语言本地化 大家肯定都多少都听过,今天我要分享的是快速实现语言本地化,与App内语言切换

核心内容主要是三个部分

  • storyboard/xib本地化

  • 纯代码本地化

  • 语言切换

准备工作

项目中添加语言

storyboard/xib本地化

storyboard/xib做本地化Xcode基本上是一键搞定了。

很简单

只要勾勾选选就可以了

这边只涉及到一个更新的问题

通过 ibtools命令 可以使storyboard/xib生成新的代码

首先cd 到stroyboard/xib 目录

执行ibtool xxx.storyboard --generate-strings-file new.strings

打开new.strings 将新内容手动复制到原来的string上。

纯代码本地化

创建string文件

勾选语言,把几种全部勾上,包括Base (为下文使用脚本生成代码做准备)


添加脚本

将脚本执行移动到编译上方


移动位置

添加脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Localizable.strings文件路径
localizableFile="${SRCROOT}/${PROJECT_NAME}/Support/en.lproj/Localizable.strings"
# 生成的swift文件路径(根据个人习惯修改)
localizedFile="${SRCROOT}/${PROJECT_NAME}/Source/Utils/LocalizedUtils.swift"
# 将localizable.strings中的文本转为swift格式的常量,存入一个临时文件
sed "s/^\"/  static var localized_/g" "${localizableFile}" | sed "s/\" = \"/: String { return \"/g" | sed "s/;$/.localized }/g" "${localizedFile}.tmp"
# 先将localized作为计算属性输出到目标文件
echo -e "import Foundation\n\nextension String {\n  var localized: String { return NSLocalizedString(self, comment: self) }" "${localizedFile}"
# 再将临时文件中的常量增量输出到目标文件
cat "${localizedFile}.tmp" >> "${localizedFile}"
# 最后增量输出一个"}"到目标文件,完成输出
echo -e "\n}" >> "${localizedFile}"
# 删除临时文件
rm "${localizedFile}.tmp"

这里需要注意的是几个目录需要对应好,否则会报错

build一下就能自动生成相关代码 就可以直接用了

语言切换

语言切换的基本原理是使用Userdefault存储当前选择的语言,在设置的时候改变其内容即可

主要涉及到两个问题

  • storyboard/xib如何切换语言

  • 如何刷新界面

对于上面都算是正常的本地化的内容,基本上介绍本地化的教程都会有。

对于自动化脚本这块算是比较新颖。

但是,脚本对于带空格的字符串生成的内容还是有问题,由于是使用sed命令,本人还不是很熟,只能想其他办法,这时候Base.lproj就派上用场了

我们将空格都替换成下划线,或者驼峰命名,在Base中一一对应,

在具体的en和zh中写具体内容,这时Base的作用就是为了方便自动生成代码而已了。(如果不想搞乱Base,新建一个即可)

关于storyboard/xib切换语言

替换Bundle即可

自定义一个Bundle,重写localizedString方法,每次都从Userdefault中获取当前选择语言,再使用方法替换将Bundle.main替换成自定义的Bundle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
enum Language : String {
    case english = "en"
    case chinese = "zh-Hans"
}
 
/**
 *  当调用onLanguage后替换掉mainBundle为当前语言的bundle
 */
 
class BundleEx: Bundle {
     
    override func localizedString(forKey key: String, value: String?, table tableName: String?) -> String {
        if let bundle = Bundle.getLanguageBundel() {
            return bundle.localizedString(forKey: key, value: value, table: tableName)
        }else {
            return super.localizedString(forKey: key, value: value, table: tableName)
        }
    }
}
 
 
extension Bundle {
     
    private static var onLanguageDispatchOnce: ()->Void = {
        //替换Bundle.main为自定义的BundleEx
        object_setClass(Bundle.main, BundleEx.self)
    }
     
    func onLanguage(){
        Bundle.onLanguageDispatchOnce()
    }
     
    class func getLanguageBundel() -> Bundle? {
        let languageBundlePath = Bundle.main.path(forResource: UserDefaults.standard[AppStatic.kCurrentLanguage] asString, ofType: "lproj")
//        print("path = \(languageBundlePath)")
        guard languageBundlePath != nil else {
            return nil
        }
        let languageBundle = Bundle.init(path: languageBundlePath!)
        guard languageBundle != nil else {
            return nil
        }
        return languageBundle!
         
    }
}

其中为Userdefault自定义了下标

1
2
3
4
5
6
7
8
    public subscript(key: String) -> Any? {
        get {
            return object(forKey: key)
        }
        set {
            set(newValue, forKey: key)
        }
    }

在读取字符串时执行一次

Bundle.main.onLanguage()

我就直接写到了脚本里,将脚本修改如下(几个文件的路径自己注意一下)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Localizable.strings文件路径
localizableFile="${SRCROOT}/Base.lproj/Localizable.strings"
# 生成的swift文件路径(根据个人习惯修改)
localizedFile="${SRCROOT}/Public/LocalizedUtils.swift"
# 将localizable.strings中的文本转为swift格式的常量,存入一个临时文件
sed "s/^\"/  static var localized_/g" "${localizableFile}" | sed "s/\" = \"/: String { return \"/g" | sed "s/;$/.localized }/g" "${localizedFile}.tmp"
# 先将localized作为计算属性输出到目标文件
echo -e "import Foundation\n\nextension String {\n  var localized: String { Bundle.main.onLanguage() \n return NSLocalizedString(self, comment: self) }" "${localizedFile}"
# 再将临时文件中的常量增量输出到目标文件
cat "${localizedFile}.tmp" >> "${localizedFile}"
# 最后增量输出一个"}"到目标文件,完成输出
echo -e "\n}" >> "${localizedFile}"
# 删除临时文件
rm "${localizedFile}.tmp"

关于刷新界面

对于所有界面的刷新最方便的就是重新设置rootViewController

将keyWindow先变黑,假装loading个几秒,再变回来即可。

如果需要再次回到之前所在页面,再添加相应的跳转VC的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
    func chooseLanguage() {
        DispatchQueue.global().async {
            let sheet = UIAlertController.init(title: String.localized_Choose_Language, message: nil, preferredStyle: .actionSheet)
             
            sheet.addAction(UIAlertAction.init(title: String.localized_English, style: .default, handler: { (action) in
                UserDefaults.standard[AppStatic.kCurrentLanguage] = Language.english.rawValue
                UIApplication.shared.keyWindow?.rootViewController = RedbotTabBar()
                UIApplication.shared.keyWindow?.alpha = 0
                AlertHelper.showHudWithMessage(message: "Setting Language...")
                DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()+1, execute: {
                    UIView.animate(withDuration: 1, animations: {UIApplication.shared.keyWindow?.alpha = 1})
                    AlertHelper.hideHudMessage()
                })
                 
            }))
            sheet.addAction(UIAlertAction.init(title: String.localized_Chinese, style: .default, handler: { (action) in
                UserDefaults.standard[AppStatic.kCurrentLanguage] = Language.chinese.rawValue
                UIApplication.shared.keyWindow?.rootViewController = RedbotTabBar()
                UIApplication.shared.keyWindow?.alpha = 0
                AlertHelper.showHudWithMessage(message: "Setting Language...")
                DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()+1, execute: {
                    UIView.animate(withDuration: 1, animations: {UIApplication.shared.keyWindow?.alpha = 1})
                    AlertHelper.hideHudMessage()
                })
            }))
            sheet.addAction(UIAlertAction.init(title: String.localized_Cancel, style: .cancel, handler: nil))
            self.present(sheet, animated: true, completion: nil)
        }
    }

至此App的语言切换与本地化就都讲完了,是不是很简单呢~~

后记

对于普通的小项目本地化的内容其实远没有那么复杂,需要替换的内容也很少,只要添加过一次语言,再添加新语言就非常简单了。


2017-09-05 10:51:23 amberoot 阅读数 2006

1. 首先要配置localizable.strings,如下图:

详细的配置过程这里就不说了,可以另行百度。今天主要说的是怎样在内部切换语言环境。


2.  新建类:LanguageHelper.swift

代码中注释已经很详细了,这里就不多说了。请看代码:

//
//  LanguageHelper.swift
//
//  Created by amberoot on 17/8/24.
//  Copyright  2017年 amberoot. All rights reserved.
//

import UIKit

class LanguageHelper: NSObject {
    //单例
    static let shareInstance = LanguageHelper()
    
    let def = UserDefaults.standard
    var bundle : Bundle?
    
    ///根据用户设置的语言类型获取字符串
    func getUserStr(key: String) -> String
    {
         // 获取本地化字符串,字符串根据手机系统语言自动切换
        let str = NSLocalizedString(key, comment: "default")
        return str
    }
    ///根据app内部设置的语言类型获取字符串
    func getAppStr(key: String) -> String
    {
        // 获取本地化字符串,字符串会根据app系统语言自动切换
        let str = NSLocalizedString(key, tableName: "Localizable", bundle: LanguageHelper.shareInstance.bundle!, value: "default", comment: "default")
        return str
    }
    
    ///设置app语言环境
    func setLanguage(langeuage: String) {
        var str = langeuage
        //如果获取不到系统语言,就把app语言设置为首选语言
        if langeuage == "" {
            //获取系统首选语言顺序
            let languages:[String] = UserDefaults.standard.object(forKey: "AppleLanguages") as! [String]
            let str2:String = languages[0]
            //如果首选语言是中文,则设置APP语言为中文,否则设置成英文
            if ((str2=="zh-Hans-CN")||(str2=="zh-Hans"))
            {
                str = "zh-Hans"
            }else
            {
                str="en"
            }
            
        }
        //语言设置
        def.set(str, forKey: "langeuage")
        def.synchronize()
        //根据str获取语言数据(因为设置了本地化,所以项目中有en.lproj和zn-Hans.lproj)
        let path = Bundle.main.path(forResource:str , ofType: "lproj")
        bundle = Bundle(path: path!)
 
    
    }
}


3. LanguageHelper.swift的应用

(1)在AppDelegate.swift中设置app的初始语言

可以获取手机系统语言来设置APP的初始语言环境,也可以根据自己的需求设置APP的初始语言环境。




(2)实际应用:配置label的text或button的title等等



参考博客地址:http://www.zhimengzhe.com/bianchengjiaocheng/swift/337155.html


2014-09-15 10:24:00 weixin_34236869 阅读数 52

上篇  

IOS APP 国际化(实现不跟随系统语言,不用重启应用,代码切换stroyboard ,xib ,图片,其他资源

介绍了纯代码刷新 实现程序内切换语言。 但效率底下,也存在一些问题。暂放弃。

第二种是 从跟视图切换 storyboard 实现 代码结合 storyboard 刷新 UI,

上篇遗留的问题是,在开发的时候我们要用到 base.lproj 和 对应语言下得.string 文件。

  方便开发(脚本实现 base storyboard 被编辑会 自动刷新对应语言的.string 文件。而不会覆盖掉之前翻译好的内容。)编译触发脚本

   but  如果我要运行程序调试在 模拟器或真机上。我就要去掉base 。把对应语言.string 文件转换为.storyboard . 因为刷新sb 文件原理上就是去 app 包种的mainbundle 中 对应语言包下找 sb 文件。加载它。 如果对应语言包下 是。string 或 没有sb 文件则会奔溃。

   来看: 这是对应 demo 工程 编译后的 app 包内容。 从 .storyboard 变成了 .storybardc  。这是xcode 编译 sb 文件后的 文件后缀名。

  应该想到 如果我把 对应的.string 文件转换为.storyboardc 文件 拷贝到 对应app 包种的.Lproj 中。 是不是就可以啦。

so  各种嗨皮的 去搞在shell 中。 使用ibtool 转换.string 文件为.storyboard。 然后 修改 .storyboard 文件后缀 .storybardc 。拷贝到 app 包中。运行 切换语言奔溃。

靠,明明在 那个路径下。就是加载不到。 郁闷了几天。

可怎么能得到.storyboardc 文件? 使用ibtool 可以做到。 到这里你会以为 转换的.storyboardc 是个文件。其实 它跟.lproj  一样是个文件夹。

      看 显示包内容。。   每个vc -> .nib 文件 还有.plist 清单。 

到此如果我们有这个脚本,那么就太幸福啦。使用base 和对应语言.string 文件 编辑 运行程序也不用去掉。脚本生成对应语言.storyboardc 文件到 

               

 对应语言下同时存在.storyboardc 和 .string  这样一切问题得宜解决。  支持重设系统语言  和  程序内切换语言。 而且开发时只关心程序逻辑 翻译复制粘贴。 剩下的一切交给脚本搞定。

  同样支持 xib 的国际化 ,工程中 可以同时用 sb 和 xib  或其中一个。

===================支持xib和sb中得图片国际化==========================

2015.4.30

demo 已更新,切换语言图片不会丢失。

说明:适用于不同语言使用相同图片在 sb 和 xib中。如果想不同语言使用不同图片在sb 和 xib 中的话,还是别折腾了吧。有那功夫还是直接在代码里写吧。

图片国际化实现过程:

      由于在xib 和 sb 中添加Img 控件并不会在 对应.string 文件里有类似这样的记录

  

及  控件id =  “图片名”。这里记录得也只是控件的文本。默认并不会对图片国际化。

其实xib 和 sb 只是个xml 文件而已,

source Code  查看。

 搜索image 可以查看ImageView 控件节点。当然也可以看到

 resources 节点。。没错,这就是xib 和 sb 用到的资源。

到这里思路就有了。我是不是可以找到这些图片 分别拷贝到 不同语言包(xx.lproj)下面和 sb 或xib 一个目录。

脚本实现为 解析xml ,在

${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH} 【参见xcode 环境变量】下找到图片,在拷贝到对应文件夹下。

so easy。

 由于当时也只是技术调研,并咩有真正做一个国际化的应用;如果有什么好需求可以在这里提...欢迎讨论和交流。

 

    最终demo 在这里 :

      https://github.com/githhhh/Test_Local_Two

 

以上还有些小不足,算是记录当时遇到的坑,推荐一个不错的解决方案:

虽然是swift ,但思路很不错。
http://blog.csdn.net/VictorMoKai/article/details/48894873

接管系统Bundle方法这样不需要在拷贝storyboardc文件到对应.lproj目录。

object_setClass(NSBundle.mainBundle(), BundleEx.self) 

找到一个oc 版本:

https://github.com/maximbilan/ios_language_manager/blob/master/README.md

 

    

 参考:

  http://www.futuresvision.net/?p=1127

http://stackoverflow.com/questions/1371351/add-files-to-an-xcode-project-from-a-script