How to change Language runtime in iphone app? - ios

I am using below code.
This code saves Locale name, but how refresh whole application with new language.
Here langcode variable is dynamic as per user selection.
NSString *langCode = #"fr";
NSArray *languages = nil;
languages = [NSArray arrayWithObject:langCode];
[[NSUserDefaults standardUserDefaults] setObject:languages forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize];
Which is remains for change the language in runtime? (From my app setting screen)

After making category on Language it will solve the issue.
.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];
}
From my setting view controller called above method of the category class and also fire post notification for whole application.
[NSBundle setLanguage:langCode];

With adding the LocalizationSystem file in your code, you'll be able to change the language in run-time.
download link
http://dl.dropbox.com/u/2917666/LocalizationSystem/LocalizationSystem.h
http://dl.dropbox.com/u/2917666/LocalizationSystem/LocalizationSystem.m
for more information http://aggressive-mediocrity.blogspot.com/2010/03/custom-localization-system-for-your.html

Store this variable in ApplicationDelegate file. Define its property and use anytime via appDelegate instance when you login. Once selection is changed, change the application bundle as you desire also modify the text and all.
put the language selection code whether in loop or button selection as per your requirement.
NSPath* path = [[NSBundle mainBundle] pathForResource:#"es" ofType:#"lproj"];
APP_DELEGATE.strLanguageSelectedFromLoginView = #"SPANISH";
or
NSPath* path = [[NSBundle mainBundle] pathForResource:#"en" ofType:#"lproj"];
APP_DELEGATE.strLanguageSelectedFromLoginView = #"ENGLISH";
and
languageBundle = [NSBundle bundleWithPath:path];
and finally load the laguageBundle.
NSBundle* languageBundle to be defined in app delegate.

Related

obj-c app is not localized programmatically

I try to change the language programmatically through the extension of NSBundle -- NSBundle setLanguage: (NSString *) language. I have several application localizations.
Some localizations work correctly, but when installing Spanish and Italian languages, instead of localized strings, I see the names of the localizable.strings parameters. The same happens with some other languages, but not with all the lines.
Tell me please what can be the problem
UPD:
here is some of the lines in English:
"CLOSE_TITLE" = "Close";
"PAYMENT_TITLE" = "Pay";
"PAYMENT_TITLE_IN" = "Deposit";
and they are also in Spanish:
"CLOSE_TITLE" = "Cerrar";
"PAYMENT_TITLE" = "Retirar";
"PAYMENT_TITLE_IN" = "Depositar";
There is code of extension:
#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 are you dragging the new localization files to the project? I found out that when you add new languages to xCode, it's best to first remove the whole folder from xCode completely and then drag everything including the new languages back all at the same time :)
As it turned out, the code had a non-printable space character so part of the parameters after this character is not translated. XСode does not display this character. This can happen if you translate through web services. When I removed this symbol in all localizations, everything worked correctly.

localizable.strings not working with Arabic string

I created a Localizable.strings file in XCode and then 2 languages in it.(english + Arabic )
I filled up these files with the language translations, but the just show translation in english, when I start with Arabic the key appear!
in my code :
NSLocalizedString("title", comment: "")
Localizable.strings(english)
"title" = "Error" ;
Localizable.strings(Arabic)
"title" = "خطأ" ;
I careated sample one and tried in Objective C.I got it.
I set "title" = "خطأ" in Arabic Localization files
"title" = "عنوان";
Now I have to change English to Arabic.
First I set the design in storyboard
Then Click Project.Choose Localization in Info
If you click the +(Below Localization) it shows the pop up view
Now choose Arabic.When click Arabic it shows window.You should click finish.
We need to create the string file for the localization now.I set string file name as LocalizationArabic
Once you create the String file it looks like below.
Then click File Inspector when pressing LocalizationArabic string file.Now click the Localization.It shows Empty Check box Arabic and English like below.
Here we must check the check box.Also when we check the check box the LocalizationArabic folder creates with three string files like below
Then I entered the language which I want to translate from English to Arabic in string file.
Finally I created the Header file for the Localization Language
The Header file name is LanguageHeader.It looks like below.
Now the code part starts here
First the Localization class of NSObject class
Localization.h
#import <Foundation/Foundation.h>
#import "LanguageHeader.h"
#interface Localization : NSObject
+(Localization *)sharedInstance;
+(NSString*) strSelectLanguage:(int)curLang;
+(NSString*) languageSelectedStringForKey:(NSString*) key;
#end
Localization.m
#import "Localization.h"
int currentLanguage,selectedrow;
#implementation Localization
+(Localization *)sharedInstance
{
static Localization *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[Localization alloc] init];
});
return sharedInstance;
}
+(NSString*) strSelectLanguage:(int)curLang{
if(curLang==ARABIC){
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:#"ar", nil]forKey:#"AppleLanguages"];
}
else{
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:#"en", nil]forKey:#"AppleLanguages"];
}
[[NSUserDefaults standardUserDefaults] synchronize];
currentLanguage=curLang;
NSString *strLangSelect = [[[NSUserDefaults standardUserDefaults]objectForKey:#"AppleLanguages"] objectAtIndex:0];
return strLangSelect;
}
+(NSString*) languageSelectedStringForKey:(NSString*) key
{
NSString *path;
NSString *strSelectedLanguage = [[[NSUserDefaults standardUserDefaults]objectForKey:#"AppleLanguages"] objectAtIndex:0];
//When we check with iPhone,iPad device it shows "en-US".So we need to change it to "en"
strSelectedLanguage = [strSelectedLanguage stringByReplacingOccurrencesOfString:#"en-US" withString:#"en"];
if([strSelectedLanguage isEqualToString:[NSString stringWithFormat: #"en"]]){
currentLanguage=ENGLISH;
selectedrow=ENGLISH;
path = [[NSBundle mainBundle] pathForResource:#"en" ofType:#"lproj"];
}
else{
currentLanguage=ARABIC;
selectedrow=ARABIC;
path = [[NSBundle mainBundle] pathForResource:#"ar" ofType:#"lproj"];
}
NSBundle* languageBundle = [NSBundle bundleWithPath:path];
NSString* str=[languageBundle localizedStringForKey:key value:#"" table:#"LocalizationArabic"];
return str;
}
#end
Then ViewController.h
#import <UIKit/UIKit.h>
#import "Localization.h"
#interface ViewController : UIViewController{
Localization *localization;
}
#property (strong, nonatomic) IBOutlet UILabel *lblTitle;
- (IBAction)actionChangeLanguageToArabic:(id)sender;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize lblTitle;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
localization = [Localization sharedInstance];
lblTitle.text = [Localization languageSelectedStringForKey:#"title"];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)actionChangeLanguageToArabic:(id)sender {
[Localization strSelectLanguage:ARABIC];
lblTitle.text = [Localization languageSelectedStringForKey:#"title"];
}
#end
Above code works perfectly.
Output Screen shot are below
When run the app first
After clicking the button

How to change my Label language Without changing my system Language When Button press?

I am creating one sample demo for changing label Language when button pressed using localization.
I have tried so many times but could not able to display different language.
My Question is I want change my Language English to other language.
I have already create Localizable.string file but not able to change language.
NOTE:Do not change system(simulator)language.
You can create a Helper class. See the class I'm using below.
LocalizeHelper.h
#import <Foundation/Foundation.h>
// some macros (optional, but makes life easy)
// Use "LocalizedString(key)" the same way you would use "NSLocalizedString(key,comment)"
#define LocalizedString(key) [[LocalizeHelper sharedLocalSystem] localizedStringForKey:(key)]
// "language" can be (for american english): "en", "en-US", "english". Analogous for other languages.
#define LocalizationSetLanguage(language) [[LocalizeHelper sharedLocalSystem] setLanguage:(language)]
#define LocalizationGetLanguage() [[LocalizeHelper sharedLocalSystem] getLanguage]
#interface LocalizeHelper : NSObject
// a singleton:
+ (LocalizeHelper*) sharedLocalSystem;
// this gets the string localized:
- (NSString*) localizedStringForKey:(NSString*) key;
//set a new language:
- (void) setLanguage:(NSString*) lang;
//get current language
- (NSString *)getLanguage;
#end
LocalizeHelper.m
#import "LocalizeHelper.h"
#import "Constants.h"
// Singleton
static LocalizeHelper* SingleLocalSystem = nil;
// my Bundle (not the main bundle!)
static NSBundle* myBundle = nil;
#implementation LocalizeHelper
//-------------------------------------------------------------
// allways return the same singleton
//-------------------------------------------------------------
+ (LocalizeHelper*) sharedLocalSystem {
// lazy instantiation
if (SingleLocalSystem == nil) {
SingleLocalSystem = [[LocalizeHelper alloc] init];
}
return SingleLocalSystem;
}
//-------------------------------------------------------------
// initiating
//-------------------------------------------------------------
- (id) init {
self = [super init];
if (self) {
// use systems main bundle as default bundle
myBundle = [NSBundle mainBundle];
}
return self;
}
//-------------------------------------------------------------
// translate a string
//-------------------------------------------------------------
// you can use this macro:
// LocalizedString(#"Text");
- (NSString*) localizedStringForKey:(NSString*) key {
// this is almost exactly what is done when calling the macro NSLocalizedString(#"Text",#"comment")
// the difference is: here we do not use the systems main bundle, but a bundle
// we selected manually before (see "setLanguage")
return [myBundle localizedStringForKey:key value:#"" table:nil];
}
//-------------------------------------------------------------
// set a new language
//-------------------------------------------------------------
// you can use this macro:
// LocalizationSetLanguage(#"German") or LocalizationSetLanguage(#"de");
- (void) setLanguage:(NSString*) lang {
// path to this languages bundle
NSString *path = [[NSBundle mainBundle] pathForResource:lang ofType:#"lproj" ];
if (path == nil) {
// there is no bundle for that language
// use main bundle instead
myBundle = [NSBundle mainBundle];
} else {
// use this bundle as my bundle from now on:
myBundle = [NSBundle bundleWithPath:path];
// to be absolutely shure (this is probably unnecessary):
if (myBundle == nil) {
myBundle = [NSBundle mainBundle];
}
}
[[NSUserDefaults standardUserDefaults] setObject:lang forKey:#"lang"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
//-------------------------------------------------------------
// get current language
//-------------------------------------------------------------
- (NSString *)getLanguage {
return [[NSUserDefaults standardUserDefaults] objectForKey:#"lang"];
}
#end
When you want to change the language from your app call this function LocalizationSetLanguage(#"fr");.
In order to get a localized string, call LocalizedString(#"string");.

Localization does not work anymore under iOS 9 / iOS 9.0.1

Since I create iOS Apps I use the following code to translate / localize my apps:
NSString *language = [[NSLocale preferredLanguages] objectAtIndex:0];
if ([language isEqualToString:#"de"]) {
// localized language
}
else { //base language
}
But since the update to iOS 9 this code does not work anymore.
All my apps are now in English.
Neither the apps I already have in the app store, nor the apps I run in the Simulator are localized anymore.
It would be great if you could tell me how I have to translate my code programmatically in iOS 9.
I could solve the problem.
If I use the following code the localization works under iOS 9.
[[NSBundle mainBundle] preferredLocalizations];
NSString *language = [[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0];
if ([language isEqualToString:#"de"]){
// localization
}
else {
//base language
}
I hope that will help some of you, too.
I would suggest to use a category class for Localizing strings for specified language which automatically detect the current language and localize the same.
Create a category class with Name
RunTimeLanguage
.h file
#import <Foundation/Foundation.h>
#interface NSBundle (RunTimeLanguage)
#define NSLocalizeString(key, comment) [[NSBundle mainBundle] runTimeLocalizedStringForKey:(key) value:#"" table:nil]
- (NSString *)runTimeLocalizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName;
#end
.m file
#import "NSBundle+RunTimeLanguage.h"
#implementation NSBundle (RunTimeLanguage)
- (NSString *)runTimeLocalizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName
{
NSString *StrCurrentLang = [[[NSUserDefaults standardUserDefaults] objectForKey:#"AppleLanguages"] objectAtIndex:0];
NSString *path= [[NSBundle mainBundle] pathForResource:StrCurrentLang ofType:#"lproj"];
NSBundle *languageBundle = [NSBundle bundleWithPath:path];
NSString *localizedString=[languageBundle localizedStringForKey:key value:key table:nil];
return localizedString;
}
#end
You can directly access the localized value by using below statement.
NSLocalizeString(#"yourText", nil)

Force localize image or image assets

As in this question, How to force NSLocalizedString to use a specific language
I can force localise by this method.
Header file
#interface NSBundle (Language)
+(void)setLanguage:(NSString*)language;
#end
Implementation
#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
After that, I need to localise image and as a result, I do like this.
Localize Asset Catalogs
Problem is when I change localisation programmatically, it never change image.
[NSBundle setLanguage:#"en"];
Only my string are changed. How shall I do? I have tried with both normal image and image in assets like this. But it doesn't work unless I really change my phone language in setting. But I need to change/force localisation programmatically and image need to be changed (not only text). May I know how to do?
I know that is an old question but still answering for future reference.
Make sure that you set your app language in the main.m, it works like a charm for the images.
OBS : Not using xcassets.
Like this:
int main(int argc, char * argv[])
{
#autoreleasepool
{
NSString *language = <Get Your Language from somewhere> // I user NSUserDefaults for that
if (language == nil)
{
// Gets the device current language
language = [[[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0] substringToIndex:2];
}
[NSBundle setLanguage:language];
return UIApplicationMain(argc, argv, nil, NSStringFromClass([YourAppDelegate class]));
}
}
Additionally I have this method on the BundleEx implementation. It is not needed for the localized images but I needed it for .html templates I had, for instance.
- (NSString *)pathForResource:(NSString *)name ofType:(NSString *)ext
{
NSBundle *bundle = objc_getAssociatedObject(self, &_bundle);
NSString *pathName = [bundle pathForResource:name ofType:ext];
return pathName ?: [super pathForResource:name ofType:ext];
}

Resources