Localization at run time for iOS app - ios

I want to change my app language at runtime. For that I had implemented the category class like
.h file.
#interface NSBundle (Language)
+ (void)setLanguage:(NSString *)language;
#end
.m file
#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);
[[NSNotificationCenter defaultCenter] postNotificationName:#"changeLanguage" object:self];
}
and at button click change the language like [NSBundle setLanguage:langCode];
but now I am bit confusing that what should I write to set label text like
lbl.text = ?
because it still need to restart my app to show effect of language .

iOS already have a localization file for multiple languages, you can find it in Localization/Localizable.strings.
In Localizable.strings (English)
"text" = "This is a text";
Then, put your setting text code in a function. So that, you can redraw the text after switching language.
func loadText() {
lbl.text = String.localizedString("text")
}
func changeLanguage() { // Change Language Notification
loadText()
}

Related

RLMResults:allObjects crash (iOS Objective-C)

I have old project written on Objective-C. Need to do migration to Realm.
I created several objects/classes inheritance from RLMObject. When I do fetching objects only with one main object type (ConnectionRealm) - working fine, but if I do add (only add, not include, not use) to project two or more another classes (inheritance from RLMObject), like as FloorRealm class, APP crash on [ConnectionRealm allObjects] without any errors.
Also ConnectionRealm contains RLMArray of FloorRealm. App still crashing.
(Can`t solve and understand this few days.) Thanks.
Connection Model:
#import <Foundation/Foundation.h>
#import <Realm/Realm.h>
#import "FloorRealm.h"
#interface ConnectionRealm : RLMObject
#property int connectionID;
#property NSString *name;
#property NSString *localIPAddress;
#property NSString *localPort;
#property NSString *remoteIPAddress;
#property NSString *remotePort;
#property NSString *userName;
#property NSString *password;
#property NSString *deviceID;
#property RLMArray <FloorRealm *> *floors;
- (instancetype)initWith:(NSString *)name
localIP:(NSString *)localIPAddress
localPort:(NSString *)lPort
remoteIP:(NSString *)remoteIPAddress
remotePort:(NSString *)rPort
userName:(NSString *)userName
password:(NSString *)password
deviceID:(NSString *)deviceID;
#end
#import "ConnectionRealm.h"
#implementation ConnectionRealm
- (instancetype)initWith:(NSString *)name
localIP:(NSString *)localIPAddress
localPort:(NSString *)lPort
remoteIP:(NSString *)remoteIPAddress
remotePort:(NSString *)rPort
userName:(NSString *)userName
password:(NSString *)password
deviceID:(NSString *)deviceID {
if (self = [super init]) {
self.connectionID = [self incrementID];
self.name = name;
self.localIPAddress = localIPAddress;
self.localPort = lPort;
self.remoteIPAddress = remoteIPAddress;
self.remotePort = rPort;
self.userName = userName;
self.password = password;
self.deviceID = deviceID;
}
return self;
}
+ (NSString *)primaryKey { return #"connectionID"; }
- (int)incrementID {
RLMResults *objects = [ConnectionRealm allObjects];
return self.connectionID = [[objects maxOfProperty:#"connectionID"] intValue] + 1;
}
#end
FloorModel:
#import <Realm/Realm.h>
#interface FloorRealm : RLMObject
#property int floorID;
#property NSInteger floorNumber;
#property NSString *floorName;
- (instancetype)initWith:(NSInteger)floorNumber floorName:(NSString *)name;
#end
RLM_ARRAY_TYPE(FloorRealm)
#import "FloorRealm.h"
#implementation FloorRealm
- (instancetype)initWith:(NSInteger)floorNumber floorName:(NSString *)name {
if (self = [super init]) {
self.floorID = [self incrementID];
self.floorNumber = floorNumber;
self.floorName = name;
}
return self;
}
+ (NSString *)primaryKey { return #"floorID"; }
- (int)incrementID {
RLMResults *objects = [FloorRealm allObjects];
return self.floorID = [[objects maxOfProperty:#"floorID"] intValue] + 1;
}
#end
[SOLVED]
RLM_ARRAY_TYPE(FloorRealm) need put on ConnectionRealm in .h after #includes. But in official docs written another.
Also: #property RLMArray <FloorRealm *><FloorRealm> *floors; instead of #property RLMArray <FloorRealm *> *floors;
I created test project with the same models and seed all errors. Strange, but in original project Xcode not showing this errors.

In App Localization iOS 8/9, English Arabic

I want to keep my app in one of the regions and I want to localize the app without changing the native language or region settings, specifically for iOS 9, is there any way to localize the app without changing ios system settings?
[NSBundle setLanguage:#"ar"];
in the main.m before #autoreleasepool
#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

Can't read string from .plist

I have created .plist where I put string which is used for google analytics and the problem is that the string can't be pass to that code in appdelegate.m where is google analytics code.
configuration.plist looks like this :
GAnalytics , string , "XXXXXXXX"
I have create the .h and .m file for it to read it
configuration.h
#import <Foundation/Foundation.h>
#interface Configuration : NSObject
+(instancetype)sharedConfig;
-(NSString *)GoogleAnalyticsID;
#end
configuration.m
#import "Configuration.h"
#interface Configuration ()
#property (strong, nonatomic) NSDictionary *config;
#end
#implementation Configuration
+(instancetype)sharedConfig
{
static Configuration *instance = nil;
if (!instance) {
instance = [[Configuration alloc] init];
}
return instance;
}
-(instancetype)init
{
self = [super init];
if (self) {
NSBundle *bundle = [NSBundle mainBundle];
NSString *configPath = [bundle pathForResource:#"Configuration" ofType:#"plist"];
self.config = [NSDictionary dictionaryWithContentsOfFile:configPath];
}
return self;
}
-(NSString *)GoogleAnalyticsID
{
return self.config[#"GAnalytics"];
}
#end
appdelegate.m
[GAI sharedInstance].trackUncaughtExceptions = YES;
[GAI sharedInstance].dispatchInterval = 20;
[[GAI sharedInstance] trackerWithTrackingId: [[Configuration sharedConfig] GoogleAnalyticsID]];

change language option in ios App

want to add a possibility to change language in application in my app, so when the current iPhone language is English. but user set turkish in app for my application I have to force my application to localize in turkish.
i am already add file to setLanguage
LocalizationSystem.h
LocalizationSystem.m
on button Action i write given below code:
if([sender tag]==0)
{
LocalizationSetLanguage(#"en");
NSString * currentL = LocalizationGetLanguage;
NSLog(#"currentL EN:%#",currentL);
}
else
{
LocalizationSetLanguage(#"tr");
NSString * currentL = LocalizationGetLanguage;
NSLog(#"currentL TR:%#",currentL);
}
this code doesn't change language. In both NSLog it prints give below line:
2014-09-11 15:54:30.640 uyarbeni[6480:70b] currentL EN:en
2014-09-11 15:54:30.640 uyarbeni[6480:70b] currentL TR:en
when i look through the code in LocalizationSystem.m file
- (void) setLanguage:(NSString*) l
{
NSLog(#"preferredLang: %#", l);
NSString *path = [[ NSBundle mainBundle ] pathForResource:l ofType:#"lproj" ];
if (path == nil)
[self resetLocalization];
else
bundle = [NSBundle bundleWithPath:path] ;
}
Please Help me to solve the problem.
But When i select language from device setting then language get change.
You will have to set property in #"AppleLanguages" to have the selected language code by setting it via NSUserDefaults.
Like so:
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:<your code>, nil] forKey:#"AppleLanguages"];
I use it in my application, to change language use: [NSBundle setLanguage:#"tr"];
To use localized resources: [[NSBundle localBundle] pathForResource:#"List" ofType:#"plist"];
Import header in ProjectName-Prefix.pch
//.h
#import <Foundation/Foundation.h>
#interface NSBundle (Language)
+ (NSBundle *)localBundle;
+ (void)setLanguage:(NSString*)language;
#end
//.m
#import "NSBundle + Language.h"
#import <objc/runtime.h>
NSString *currentLanguage;
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)
+ (NSBundle *)localBundle
{
if (currentLanguage)
{
NSString *path = [[NSBundle mainBundle] pathForResource:currentLanguage ofType:#"lproj"];
return [NSBundle bundleWithPath:path];
}
else
{
return [NSBundle mainBundle];
}
}
+(void)setLanguage:(NSString*)language
{
currentLanguage = 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

Archiving (NSCoding) when using cocos2d - EXC_BAD_ACCESS

I'm making a game using Cocos2d-iphone 2.1, and have encountered an error with NSCoding unarchiving implementation.
I've used the same pattern in my previous projects (made with UIKit), and everything worked perfetly. While when I'm implementing this pattern on cocos2d, it just doesn't work.
I have recreated the error on a sample project (which can be downloaded here https://www.dropbox.com/sh/30cyfczcxeyf8mr/uDcJiNYMdd ) and here's what I'm doing:
I've created a simple singleton class "GameStore".
Then I've created the "GameParameters" class which is a property of the singleton and conforms to NSCoding (therefore can be archived).
In that class there's the "highscore" property of type int (for example) which I'd like to keep archived as a high score value.
In the GameStore class I initialize the GameParameters instance for the first time, if there's an archived object - I unarchive it.
In the "HelloWorldLayer" (which is a default cocos2d placeholder class) I call NSLog to display the "highscore" value and then set it to a new value
In AppDelegate I call the "save data" method to archive data whenever the home button is pressed.
That's it.
When I start the app for the first time, everything works well, and I save the data by pressing the home button.
And when I start the app again, I run into random (as it seems) EXT_BAD_ACCESS errors... Sometimes when I'm getting the highscore value, sometimes when archiving it again.
Any idea what I might be doing wrong here?
Thanks!
GameStore class
Header file:
#import <Foundation/Foundation.h>
#class GameParameters;
#interface GameStore : NSObject
#property (retain, nonatomic) GameParameters * parameters;
+ (GameStore *) game;
- (void) saveData;
#end
Implementation file:
#import "GameStore.h"
#import "GameParameters.h"
static GameStore * game = nil;
#implementation GameStore
#synthesize parameters;
+ (GameStore *) game
{
if (!game) game = [[super allocWithZone:nil] init];
return game;
}
- (id) init
{
if (game != nil) {
return game;
}
self = [super init];
if (self) {
// Initialization
// Try and load the "GameParameters" from archive
parameters = [NSKeyedUnarchiver unarchiveObjectWithFile:[self archivePath]];
NSLog(#"Highscore: %i",parameters.highscore);
// If there's no archive, initialize the "GameParameters"
if (!parameters) {
parameters = [[GameParameters alloc] init];
parameters.highscore = 12345;
}
}
return self;
}
- (void) saveData
{
[NSKeyedArchiver archiveRootObject:parameters toFile:[self archivePath]];
NSLog(#"Data saved");
}
- (NSString *)archivePath
{
NSArray * documentDirs = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString * documentDir = [documentDirs objectAtIndex:0];
return [documentDir stringByAppendingPathComponent:#"hs.archive"];
}
#end
GameParameters class
Header file:
#import <Foundation/Foundation.h>
#interface GameParameters : NSObject <NSCoding>
#property (nonatomic, assign) int highscore;
#end
Implementation file:
#import "GameParameters.h"
#implementation GameParameters
#synthesize highscore;
- (id) initWithCoder:(NSCoder *)aDecoder
{
highscore = [aDecoder decodeIntForKey:#"1"];
return self;
}
- (void) encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeInt:highscore forKey:#"1"];
}
#end

Resources