Skip to content

Instantly share code, notes, and snippets.

@epologee
Created October 11, 2013 19:26
Show Gist options
  • Save epologee/6940612 to your computer and use it in GitHub Desktop.
Save epologee/6940612 to your computer and use it in GitHub Desktop.
Use method swizzling to change both language and locale at runtime, to use in your unit tests.
#import <Foundation/Foundation.h>
@interface NSBundle (TTTOverrideLanguage)
+ (void)ttt_overrideLanguage:(NSString *)language;
+ (void)ttt_resetLanguage;
@end
#import "NSBundle+TTTOverrideLanguage.h"
#import "NSObject+TTTSwizzling.h"
@implementation NSBundle (TTTOverrideLanguage)
+ (void)load
{
[self ttt_swizzleLanguageBundles];
}
+ (void)ttt_swizzleLanguageBundles
{
[self ttt_swizzleInstanceMethod:@selector(localizedStringForKey:value:table:)
withReplacement:@selector(ttt_localizedStringForKey:value:table:)];
}
static NSBundle *ttt_languageBundle = nil;
+ (void)ttt_overrideLanguage:(NSString *)language
{
NSString *path = [[NSBundle mainBundle] pathForResource:language ofType:@"lproj"];
ttt_languageBundle = [NSBundle bundleWithPath:path];
}
+ (void)ttt_resetLanguage
{
ttt_languageBundle = nil;
}
- (NSString *)ttt_localizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName NS_FORMAT_ARGUMENT(1);
{
if (ttt_languageBundle)
{
return [ttt_languageBundle ttt_localizedStringForKey:key value:value table:tableName];
}
return [self ttt_localizedStringForKey:key value:value table:tableName];
}
@end
#import <Foundation/Foundation.h>
@interface NSLocale (TTTOverrideLocale)
+ (void)ttt_overrideRuntimeLocale:(NSLocale *)locale;
+ (void)ttt_resetRuntimeLocale;
@end
#import "NSLocale+TTTOverrideLocale.h"
#import "NSObject+TTTSwizzling.h"
#import <objc/runtime.h>
@implementation NSLocale (TTTOverrideLocale)
+ (void)load
{
[self ttt_swizzleLocales];
}
static NSLocale *ttt_locale = nil;
+ (void)ttt_overrideRuntimeLocale:(NSLocale *)locale
{
ttt_locale = locale;
}
+ (void)ttt_resetRuntimeLocale
{
ttt_locale = nil;
}
+ (void)ttt_swizzleLocales
{
[self ttt_swizzleClassMethod:@selector(autoupdatingCurrentLocale) withReplacement:@selector(ttt_autoupdatingCurrentLocale)];
[self ttt_swizzleClassMethod:@selector(currentLocale) withReplacement:@selector(ttt_currentLocale)];
[self ttt_swizzleClassMethod:@selector(systemLocale) withReplacement:@selector(ttt_systemLocale)];
}
+ (id /* NSLocale * */)ttt_autoupdatingCurrentLocale
{
return ttt_locale ?: [self ttt_autoupdatingCurrentLocale];
}
+ (id /* NSLocale * */)ttt_currentLocale
{
return ttt_locale ?: [self ttt_currentLocale];
}
+ (id /* NSLocale * */)ttt_systemLocale
{
return ttt_locale ?: [self ttt_systemLocale];
}
@end
#import <Foundation/Foundation.h>
@interface NSObject (TTTSwizzling)
+ (void)ttt_swizzleClassMethod:(SEL)original withReplacement:(SEL)swizzled;
+ (void)ttt_swizzleInstanceMethod:(SEL)original withReplacement:(SEL)swizzled;
@end
#import <objc/runtime.h>
#import "NSObject+TTTSwizzling.h"
@implementation NSObject (TTTSwizzling)
+ (void)ttt_swizzleClassMethod:(SEL)original withReplacement:(SEL)swizzled
{
method_exchangeImplementations(class_getClassMethod(self, original), class_getClassMethod(self, swizzled));
}
+ (void)ttt_swizzleInstanceMethod:(SEL)original withReplacement:(SEL)swizzled
{
method_exchangeImplementations(class_getInstanceMethod(self, original), class_getInstanceMethod(self, swizzled));
}
@end
@emartynov
Copy link

Hi!

I'm not expert in swizzling. Why do we have recursive call if for example ttt_locale is nil? Would it be stackoverflow?

@Ricardo1980
Copy link

Nope. The code is correct. Review swizzling again.

@thomasaw
Copy link

With modernized Objective-C id /* NSLocale * */ can be replaced with instancetype.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment