iOS国际化

https://github.com/starainDou 欢迎点星

NSLocalizedString

Xcode中有本地化的内置支持

  • NSLocalizedString的定义:
#define NSLocalizedString(key, comment) \
[[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:nil]

第一个参数key是从Localizable.strings这个文件中读取对应的key-value值。
第二个参数comment可以是nil,可以是一段为空的字符串,也可以是对key的注释。

  • 本地化字符串

添加语言支持

AddLanguage.png

建立String File文件,命名命名为“Localizable,生成一个Localizable.strings文件(名字不要其他的)

Localizable.png

选中新建的Localizable.strings文件,点击右边的Localize,添加English和Chinese

Localize.png

在Localizable.strings(English) 文件中写 "OK" = "OK";(不要忘记写分号)
在Localizable.strings(Chinese) 文件中写 "OK" = "确定";(不要忘记写分号)

使用

define OKText NSLocalizedString(@"OK", nil)

如果你的strings文件名字不是Localizable而是自定义的话,如hel.strings,那么你就得使用NSLocalizedStringFromTable()来读取本地化字符串 NSLocalizedStringFromTable(@"hello",@"hel", nil)

如果不能添加语言支持(localizations--choose files and reference language to create...为空白)

打开工程配置,搜 /* Begin XCBuildConfiguration section */
在之前添加段落

/* Begin PBXVariantGroup section /
4C0E56D11F09E6B900583071 /
Localizable.strings / = {
isa = PBXVariantGroup;
children = (
4C0E56D01F09E6B900583071 /
en /,
4C0E56D21F09E6C200583071 /
zh-Hans /,
);
name = Localizable.strings;
sourceTree = "<group>";
};
ABCB97AC1D71D063000DEBEF /
LaunchScreen.storyboard / = {
isa = PBXVariantGroup;
children = (
ABCB97AD1D71D063000DEBEF /
Base /,
4C0E56CC1F09E37B00583071 /
zh-Hans /,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/
End PBXVariantGroup section */

然后添加直接添加Localizable.strings,方法见上,不考虑别的问题,然后回到配置文件搜索
/* Localizable.strings in Resources /
复制ID
搜/
Begin PBXVariantGroup section /,将/ Localizable.strings */ 前面的ID 替换保存即可

XCBuildConfiguration

封装的工具,在APP内切换语言

你可以用黑魔法为全局添加,不过需要处理很多特殊情况。

DDYLanguageTool.h

/**
 *  语言国际化使用方式
 *  1.AppDelegata中 -application:didFinishLaunchingWithOptions: 里设置默认(初始化即可)   [DDYLanguageTool sharedManager];
 *  2.选择语言后 [[DDYLanguageTool sharedManager] ddy_SetLanguage:_selectLanguage callback:nil];
 */

#import <Foundation/Foundation.h>

/** 英汉双语 */
#if TARGET_IPHONE_SIMULATOR
#define DDYStr(Chinese,English) [DDYCurrentLanguage isEqualToString:IOS_9_LATER?@"zh-Hans-US":@"zh-Hans"] ? Chinese : English
#elif TARGET_OS_IPHONE
#define DDYStr(Chinese,English) [DDYCurrentLanguage isEqualToString:IOS_9_LATER?@"zh-Hans-CN":@"zh-Hans"] ? Chinese : English
#endif


extern NSErrorDomain DDYLanguageErrorDomain;
#define kDDYLanguageErrorSuccess       0  // 设置语言成功
#define kDDYLanguageErrorUnknown      -1  // 未知错误
#define kDDYLanguageErrorNil          -2  // 语言为空
#define kDDYLanguageErrorNotSupport   -3  // 不支持的语言

static NSString *const DDY_CN  = @"zh-Hans";
static NSString *const DDY_EN  = @"en";

@interface DDYLanguageTool : NSObject

/** 单例对象 */
+ (instancetype)sharedManager;

/** 获取当前语言 */
- (NSString *)localLanguage;

/** 切换语言(汉英时) */
- (void)changeLanguage;

/** 设置语言(较多语言支持时) */
- (void)ddy_SetLanguage:(NSString *)language callback:(void (^)(NSError *error))callback;

@end

DDYLanguageTool.m


#import "DDYLanguageTool.h"
#import <objc/runtime.h>

#define DDYLanguageSet @"DDYLanguageSet"

NSErrorDomain DDYLanguageErrorDomain = @"DDYLanguageErrorDomain";


//----------------------- NSBundle子类 -----------------------//
static const char _bundle = 0;

@interface DDYBundleExt : NSBundle

@end

@implementation DDYBundleExt

- (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 DDYLanguageTool


#pragma mark - 单例对象
static DDYLanguageTool *_instance;

+ (instancetype)sharedManager {
    return [[self alloc] init];
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [super allocWithZone:zone];
    });
    return _instance;
}

- (id)copyWithZone:(NSZone *)zone {
    return _instance;
}

- (id)mutableCopyWithZone:(NSZone *)zone {
    return _instance;
}

#pragma mark 初始化
- (instancetype)init {
    if (self = [super init]) {
        NSString *currLanguage = DDYUserDefaultsGet(DDYLanguageSet);
        // 默认语言(中英)
        if (!currLanguage) {
            currLanguage = DDYStr(DDY_CN, DDY_EN);
        }
        DDYUserDefaultsSet(currLanguage, DDYLanguageSet)
        [DDYUserDefaults synchronize];
        [self setLanguage:currLanguage];
    }
    return self;
}

#pragma mark 获取当前语言
- (NSString *)localLanguage {
    return DDYUserDefaultsGet(DDYLanguageSet);
}

#pragma mark 切换语言(中英时)
- (void)changeLanguage {
    [DDYUserDefaults setObject:[DDYUserDefaultsGet(DDYLanguageSet) isEqualToString:DDY_CN] ? DDY_EN : DDY_CN forKey:DDYLanguageSet];
    [DDYUserDefaults synchronize];
}

#pragma mark 设置语言(较多语言支持时)
- (void)ddy_SetLanguage:(NSString *)language callback:(void (^)(NSError *error))callback {
    if ([language ddy_blankString]) {
        if (callback) callback([NSError errorWithDomain:DDYLanguageErrorDomain code:kDDYLanguageErrorNil userInfo:@{@"reason":@"设置的语言不能为空"}]);
    } else {
        [self setLanguage:language];
        [DDYUserDefaults setObject:language forKey:DDYLanguageSet];
        [DDYUserDefaults synchronize];
        if (callback) callback([NSError errorWithDomain:DDYLanguageErrorDomain code:kDDYLanguageErrorSuccess userInfo:@{@"reason":@"设置成功"}]);
    }
}

#pragma mark 私有方法 设置语言
- (void)setLanguage:(NSString *)language {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        object_setClass([NSBundle mainBundle], [DDYBundleExt class]);
    });
    
    objc_setAssociatedObject([NSBundle mainBundle], &_bundle, language ? [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:language ofType:@"lproj"]] : nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

@end

码农不易,点个星星支持下吧 DDYLanguageTool

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,667评论 5 472
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,361评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,700评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,027评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,988评论 5 361
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,230评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,705评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,366评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,496评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,405评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,453评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,126评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,725评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,803评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,015评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,514评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,111评论 2 341

推荐阅读更多精彩内容

  • Demo同步更新到Swift2.3本文地址: http://mokai.me/iOS-i18n.html 在真正...
    _GKK_阅读 5,775评论 13 55
  • 国际化(Internationalization ,简写为I18N)的作用是防止将本土文化信息写死仔应用里(所谓本...
    西西西瓜啊阅读 11,230评论 23 15
  • ** 原文发表在:https://www.xiaolei0808.com/2016/04/24/Localized...
    金小白先生阅读 17,522评论 16 90
  • 之前公司的app可能要在岛国和东南亚地区使用,所以最合理的方法就是--国际化。 写这篇文章也是为一个妹子写的(咦~...
    伦敦乡下的小作家阅读 789评论 4 4
  • 一、简介 所谓国际化就是让你的APP能在不同国家的人们都能看懂,即让你APP中的语言跟随系统变化,若系统当前语言是...
    小道萧兮阅读 4,052评论 0 4