change language option in ios App - ios

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

Related

Localization at run time for iOS app

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()
}

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

How to get localised storyboard strings after switching to language at runtime in IOS?

I have following code to switch language runtime:
-(void) switchToLanguage:(NSString *)lang{
self.language = lang;
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:self.language, nil]
forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
And I have a Helper function that retrieves localised strings:
+(NSString *) getLocalizedString:(NSString *)key{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSString *path = [[NSBundle mainBundle] pathForResource:#"Localizable"
ofType:#"strings"
inDirectory:nil
forLocalization:appDelegate.language];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
return [dict objectForKey:key];
}
This is working. My storyboards are also localised, but they are not changing when I switch to another language.
How can I get localised values for the storyboard strings?
Changing the Language at run time is a bit tricky.
This is the best way I've used to do so with the help of this tiny class:
Language.m:
#import "Language.h"
#implementation Language
static NSBundle *bundle = nil;
+(void)initialize {
NSUserDefaults* defs = [NSUserDefaults standardUserDefaults];
NSArray* languages = [defs objectForKey:#"AppleLanguages"];
NSString *current = [languages objectAtIndex:0];
[self setLanguage:current];
}
+(void)setLanguage:(NSString *)l
{
NSString *path = [[ NSBundle mainBundle ] pathForResource:l ofType:#"lproj" ];
bundle = [NSBundle bundleWithPath:path];
}
+(NSString *)get:(NSString *)key alter:(NSString *)alternate
{
return [bundle localizedStringForKey:key value:alternate table:nil];
}
#end
Language.h:
import <Foundation/Foundation.h>
#interface Language : NSObject
+(void)setLanguage:(NSString *)l;
+(NSString *)get:(NSString *)key alter:(NSString *)alternate;
#end
When you want to change the Language:
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:#"en", #"de", nil] forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize];
[Language setLanguage:#"en"];
[(AppDelegate *)[[UIApplication sharedApplication] delegate] window].rootViewController = [self.storyboard instantiateInitialViewController];
When you want to set a string:
[self.someButton setTitle:[Language get:#"Some Button Text" alter:nil] forState:UIControlStateNormal];

Identify if users are upgrading or installing new version of app for the first time

I want to know whether my users are downloading my application for the first time or upgrading the old version.
How can I get that information when application is launched?
Option 1.
Save the bundle version somewhere and check if it differs from
[[NSBundle mainBundle] objectForInfoDictionaryKey:#"CFBundleVersion"]]
on each app startup.
Option 2.
Use a category on UIApplication that let's you see if the app was updated.
UIApplication+Versioning.h
#protocol UIApplicationDelegate<UIApplicationDelegate>
#optional
- (void)application:(UIApplication *)application
willUpdateToVersion: (NSString*) newVersion
fromVersion: (NSString*) previousVersion;
- (void)application:(UIApplication *)application
didUpdateToVersion: (NSString*) newVersion
fromVersion: (NSString*) previousVersion;
#end
#interface UIApplication (Versioning)
#end
UIApplication+Versioning.m
#import "UIApplication+Versioning.h"
#import <objc/message.h>
#import <objc/runtime.h>
static NSString* UIApplicationVersionFileName = #"app.version";
#implementation UIApplication (Versioning)
+ (void)load
{
original = class_getInstanceMethod(self, #selector(setDelegate:));
swizzled = class_getInstanceMethod(self, #selector(swizzled_setDelegate:));
method_exchangeImplementations(original, swizzled);
}
- (void)swizzled_setDelegate:(id<UIApplicationDelegate>)delegate
{
IMP implementation = class_getMethodImplementation([self class], #selector(swizzled_application:didFinishLaunchingWithOptions:));
class_addMethod([delegate class], #selector(swizzled_application:didFinishLaunchingWithOptions:), implementation, "B#:##");
original = class_getInstanceMethod([delegate class], #selector(application:didFinishLaunchingWithOptions:));
swizzled = class_getInstanceMethod([delegate class], #selector(swizzled_application:didFinishLaunchingWithOptions:));
method_exchangeImplementations(original, swizzled);
[self swizzled_setDelegate: delegate];
}
- (BOOL)swizzled_application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Check for a version change
NSError* error;
NSArray* directories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* versionFilePath = [[directories objectAtIndex: 0] stringByAppendingPathComponent:UIApplicationVersionFileName];
NSString* oldVersion = [NSString stringWithContentsOfFile:versionFilePath
encoding:NSUTF8StringEncoding
error:&error];
NSString* currentVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey: #"CFBundleVersion"];
switch (error.code)
{
case NSFileReadNoSuchFileError:
{
// Delegate methods will not be called first time
oldVersion = [currentVersion copy];
[currentVersion writeToFile: versionFilePath
atomically: YES
encoding: NSUTF8StringEncoding
error: &error];
break;
}
default:
{
NSLog(#"Warning: An error occured will loading the application version file -> Recreating file");
[[NSFileManager defaultManager] removeItemAtPath: versionFilePath
error: nil];
oldVersion = [currentVersion copy];
[currentVersion writeToFile: versionFilePath
atomically: YES
encoding: NSUTF8StringEncoding
error: &error];
break;
}
}
if( ![oldVersion isEqualToString: currentVersion] )
{
if ([[application delegate] respondsToSelector: #selector(application:willUpdateToVersion:fromVersion:)])
{
objc_msgSend([application delegate], #selector(application:willUpdateToVersion:fromVersion:), currentVersion, oldVersion);
}
[currentVersion writeToFile:versionFilePath
atomically:YES
encoding:NSUTF8StringEncoding
error:&error];
if ([[application delegate] respondsToSelector: #selector(application:didUpdateToVersion:fromVersion:)])
{
objc_msgSend([application delegate], #selector(application:willUpdateToVersion:fromVersion:), currentVersion, oldVersion);
}
}
SEL realSelector = #selector(swizzled_application:didFinishLaunchingWithOptions:);
return (BOOL) objc_msgSend([application delegate], realSelector, application, launchOptions);
}
#end

iOS Localize app manually then switch

I have been facing a problem with iOS Programming since its the first time I'm using Localization,,
I used the following to know which lang I'm having:
- (NSString*) getLanguage{
NSArray* languages = [[NSUserDefaults standardUserDefaults] objectForKey:#"AppleLanguages"];
NSString *preferredLang = [languages objectAtIndex:0];
return preferredLang;}
and there is button to change the lang That calls function to change the lang
- (void) setLanguage:(NSString*) l{
[[NSUserDefaults standardUserDefaults] setObject: [NSArray arrayWithObjects:l, nil] forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults]synchronize];}
The language changes successfully, but I need to close and reopen the app to see the result, is there any other way to change the localisation automatically after switching lang?
NOTE: it should woke with storyboards too.
As #Tudorizer describes in this link after you translate your files
use this solution:
Put this macro in the Prefix.pch:
#define currentLanguageBundle [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[[NSLocale preferredLanguages] objectAtIndex:0] ofType:#"lproj"]]
and where ever you need a localized string use:
NSLocalizedStringFromTableInBundle(#"GalleryTitleKey", nil, currentLanguageBundle, #"");
To set the language use:
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:#"de"] forKey:#"AppleLanguages"];
Multiple times:
NSLog(#"test %#", NSLocalizedStringFromTableInBundle(#"NewKey", nil, currentLanguageBundle, #""));
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:#"fr"] forKey:#"AppleLanguages"];
NSLog(#"test %#", NSLocalizedStringFromTableInBundle(#"NewKey", nil, currentLanguageBundle, #""));
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:#"it"] forKey:#"AppleLanguages"];
NSLog(#"test %#", NSLocalizedStringFromTableInBundle(#"NewKey", nil, currentLanguageBundle, #""));
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:#"de"] forKey:#"AppleLanguages"];
NSLog(#"test %#", NSLocalizedStringFromTableInBundle(#"NewKey", nil, currentLanguageBundle, #""));
You can switch between languages in your application using the following class:
(Note that anyway you should refresh content of all controllers stored in memory to get full effect.)
// AMLocalization.h
#define SetAppLanguage(language) [[AMLocalization sharedLocalization] setLanguage:language]
#define GetAppLanguage() [[AMLocalization sharedLocalization] language]
#define LSC(key, comment) [[AMLocalization sharedLocalization] localizedStringForKey:(key) value:(comment)]
#define UDKeyAppLanguage #"UDKeyAppLanguage"
typedef enum {
UILanguageUnknown,
UILanguageEnglish,
UILanguageFrench,
..................
} UILanguage;
#interface AMLocalization : NSObject
+ (AMLocalization *)sharedLocalization;
- (NSString *)localizedStringForKey:(NSString *)key value:(NSString *)comment;
- (BOOL) setLanguage:(UILanguage) lang;
- (UILanguage) language;
#end
// AMLocalization.m
#import "AMLocalization.h"
static AMLocalization *_s_sharedLocalization = nil;
#implementation AMLocalization {
NSBundle *_bundle;
NSDictionary *_languageSet;
}
+ (AMLocalization *)sharedLocalization
{
static dispatch_once_t once;
dispatch_once(&once, ^{
_s_sharedLocalization = [AMLocalization new];
});
return _s_sharedLocalization;
}
- (id) init
{
if (self = [super init]) {
_bundle = [NSBundle mainBundle];
_languageSet = #{
#(UILanguageEnglish) : #"en",
#(UILanguageFrench) : #"fr"
};
}
return self;
}
- (NSString *)localizedStringForKey:(NSString *)key value:(NSString *)comment
{
return [_bundle localizedStringForKey:key value:comment table:nil];
}
- (BOOL) setLanguage:(UILanguage) lang
{
UILanguage activeLang = [self language];
if (lang == UILanguageUnknown) {
_bundle = [NSBundle mainBundle];
[[NSUserDefaults standardUserDefaults] removeObjectForKey:UDKeyAppLanguage];
}
else {
NSString *path = [[NSBundle mainBundle] pathForResource:_languageSet[#(lang)] ofType:#"lproj"];
_bundle = [NSBundle bundleWithPath:path];
[[NSUserDefaults standardUserDefaults] setInteger:lang forKey:UDKeyAppLanguage];
}
[[NSUserDefaults standardUserDefaults] synchronize];
return activeLang != lang;
}
- (UILanguage) language
{
UILanguage lang = [[NSUserDefaults standardUserDefaults] integerForKey:UDKeyAppLanguage];
if (lang == UILanguageUnknown) {
NSString* preferredLang = [[NSUserDefaults standardUserDefaults] objectForKey:#"AppleLanguages"][0];
for (NSNumber *key in _languageSet) {
if ([_languageSet[key] isEqualToString:preferredLang]) {
lang = [key integerValue];
break;
}
}
}
return lang;
}
#end

Resources