On iPhone NSLocalizedString
returns the string in the language of the iPhone.
Is it possible to force NSLocalizedString
to use a specific language to have the app
in a different language than the device ?

- 3,321
- 2
- 27
- 52

- 3,671
- 3
- 25
- 28
-
Please refer this : https://stackoverflow.com/a/48187049/6665075 Works like a charm – Ankit Kumar Gupta Jan 10 '18 at 12:28
28 Answers
NSLocalizedString()
(and variants thereof) access the "AppleLanguages" key in NSUserDefaults
to determine what the user's settings for preferred languages are. This returns an array of language codes, with the first one being the one set by the user for their phone, and the subsequent ones used as fallbacks if a resource is not available in the preferred language. (on the desktop, the user can specify multiple languages with a custom ordering in System Preferences)
You can override the global setting for your own application if you wish by using the setObject:forKey: method to set your own language list. This will take precedence over the globally set value and be returned to any code in your application that is performing localization. The code for this would look something like:
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"de", @"en", @"fr", nil] forKey:@"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize]; //to make the change immediate
This would make German the preferred language for your application, with English and French as fallbacks. You would want to call this sometime early in your application's startup. You can read more about language/locale preferences here: Internationalization Programming Topics: Getting the Current Language and Locale

- 14,073
- 11
- 62
- 81

- 11,915
- 4
- 44
- 58
-
4This does not work for me, it will use the default language no matter what. – quano Feb 22 '10 at 17:41
-
2This didn't work for me, so I used, [[NSUserDefaults standardUserDefaults] setObject: [NSArray arrayWithObjects:@"el", nil] forKey:@"AppleLanguages"]; – Panagiotis Korros Mar 08 '10 at 13:32
-
1Didn't work for me either, but [[NSUserDefaults standardUserDefaults] setObject: [NSArray arrayWithObjects:@"el", nil] forKey:@"AppleLanguages"]; *did*. (NB. you have to restart the App for it to take affect)- Thanks Panagiotis Korros! [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"AppleLanguages"]; to undo, and go back to the default language – William Denniss Mar 10 '10 at 15:04
-
51Denniss; It seems to work better if you set the language preference *before* the app is launched. I do it in the main() function, before UIApplicationMain() is called. Once it is actually running, it won't change the used language, but just set the preference for the next time. – geon Sep 01 '10 at 21:44
-
3You have to set the language before you initialize UIKit and you must specify a complete language+region locale - check this out for a complete example http://blog.federicomestrone.com/2010/09/15/iphone-apps-and-device-language-setting/ – fedmest Apr 21 '11 at 09:16
-
-
The keyboard is not localized, i'm still getting english version. Could anybody help with this. – satish Oct 12 '12 at 07:34
-
@geon and @"Brian Webster", thanks very much. I've got what I needed to assist testing my app for different language settings without having to go through the Internationalisation Settings. – Jason TEPOORTEN Mar 17 '13 at 02:03
-
18setting AppleLanguages will change a language at runtime if done in main() - true! but... the FIRST TIME the app is installed, the nsuserdefaults are initialized AFTER UIApplicationMain() is called, which will ignore the previously set AppleLanguages and will require an ugly force-restart of the app to see the desired language. – JohnPayne Sep 09 '13 at 01:02
-
Also make sure to remove the "AppleLanguages" key just AFTER UIApplicationMain() is called, i.e. in applicationDidEnterBackground in AppDelegate. This so the user can change language manually later! – Sunkas Nov 19 '14 at 14:16
-
I am doing same above code also reintialized UIviews but app's language not reflected instantly. If pressed HOME & again starting app then also not changing language. If app run another time from xcode then it is working. What is missing? – Shah Nilay Dec 19 '14 at 12:45
-
Looks like non of these solutions will flip the layout of the views for the rtl languages without a restart. right? – hasan Jan 12 '15 at 14:45
-
How did you know how to do this??! Amazing. Anyway, translated to Swift here: http://stackoverflow.com/a/33685575/8047 – Dan Rosenstark Nov 13 '15 at 03:45
-
-
3This doesn't work with plural items defined in Localizable.stringsdict. Any idea if there's a possible fix? – Mihai Fratu Dec 08 '15 at 23:37
-
-
Avoid the key AppleLanguages. The key is used internally for Xcode for debugging purposes and might break with new SDK releases. Starting from iOS 13 use preferred languages: https://www.reddit.com/r/iOSBeta/comments/bxfkzm/feature_preferred_language_allows_individual_apps/ If you're supporting pre iOS 13 versions prefer a custom solution where the behavior is testable and does not rely on private implementations. – Botond Magyarosi Apr 12 '20 at 13:11
I had the same problem recently and I didn't want to start and patch my entire NSLocalizedString nor force the app to restart for the new language to work. I wanted everything to work as-is.
My solution was to dynamically change the main bundle's class and load the appropriate bundle there:
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
So basically, when your app starts and before you load your first controller, simply call:
[NSBundle setLanguage:@"en"];
When your user changes his preferred language in your setting screen, simply call it again:
[NSBundle setLanguage:@"fr"];
To reset back to system defaults, simply pass nil:
[NSBundle setLanguage:nil];
Enjoy...
For those who need a Swift version:
var bundleKey: UInt8 = 0
class AnyLanguageBundle: Bundle {
override func localizedString(forKey key: String,
value: String?,
table tableName: String?) -> String {
guard let path = objc_getAssociatedObject(self, &bundleKey) as? String,
let bundle = Bundle(path: path) else {
return super.localizedString(forKey: key, value: value, table: tableName)
}
return bundle.localizedString(forKey: key, value: value, table: tableName)
}
}
extension Bundle {
class func setLanguage(_ language: String) {
defer {
object_setClass(Bundle.main, AnyLanguageBundle.self)
}
objc_setAssociatedObject(Bundle.main, &bundleKey, Bundle.main.path(forResource: language, ofType: "lproj"), .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}

- 3
- 2

- 4,546
- 4
- 41
- 58
-
Any experience with this? Does it work? Gilad, are you still using this successfully? – Wirsing Mar 25 '14 at 07:47
-
7Hi @Wirsing , this works great for me so far. I've even uploaded one app to the store and no complains by Apple. – Gilad Novik Mar 25 '14 at 18:04
-
8This is a great solution, I've also referencing this here: https://medium.com/ios-apprentice/905e4052b9de – James Tang May 06 '14 at 08:34
-
1Hi @JamesTang , Thanks for the reference and your post - I found a lot of useful information there regarding localization. – Gilad Novik May 07 '14 at 03:55
-
3@Gilad your method works perfect for dynamic strings (strings that i defined in localizable.strings) but as for storyboard buttons and labels it only work at main method only. so can you extend your answer to include UI controls localization? i mean how to refresh (without closing) storyboard after i invoke [NSBundle setLanguage:@"??"];? – Jawad Al Shaikh May 14 '14 at 09:09
-
2As for XIB/storyboard: you need to make sure you call this method BEFORE you load the view. As far updating views live: in my case I simply reloaded the view controller (I put it in a navigation controller and just replaced the controller. Upon reloading it - it got the new translated strings). I'm working on a cocoapod for it, I'll probably include an example there as well. Stay tuned... – Gilad Novik May 14 '14 at 21:42
-
@Gilad its working perfectly on Strings but the problem come when using localized xib view!! – mohammad alabid May 14 '14 at 22:02
-
based on @JamesTang posted link: storyboard refresh through controller can be done with: including appDelegate.h then: appDelegate *delg = [UIApplication sharedApplication].delegate; delg.window.rootViewController=[self.storyboard instantiateInitialViewController]; above two lines will reset storyboard to idle case, so make sure no activities going on while doing that, also you need to store the current lang somewhere instead of having 'en' as default everytime app is booted... – Jawad Al Shaikh May 15 '14 at 10:31
-
This worked for me, just load the XIB manually, it may be not perfect solution but it will help http://stackoverflow.com/questions/8712049/manually-loading-a-different-localized-nib-in-ios @Gilad Thanks for your help – mohammad alabid May 15 '14 at 17:30
-
1@mohammadalabid there is really no need to load the language manually - I've successfully used this code with XIB's as well. My trick was to have the root controller as a UINavigationController and right after I change the language - I use its 'viewControllers' property to reload the XIB. rootNavigationController.viewControllers=@[[storyboard instantiateViewControllerWithIdentifier:@"main"]]; I'll post an example to github soon. – Gilad Novik May 15 '14 at 17:50
-
-
1Hi this is great. It work for me. But it doesn't work for image. I have asked here. Can anyone help me please? http://stackoverflow.com/questions/25379056/force-localize-image-or-image-assets – Khant Thu Linn Aug 19 '14 at 08:58
-
Hi Gilad, thanks for the great solution but in my case its changing the text but not alignment from LTR to RTL on arabic selection. Working with proper AutoLayout and RTL alignment is working when user changes language of his device from device setting. – Muhammad Saad Ansari Apr 08 '15 at 08:41
-
Its working , but it not set those text which is set from didfinishlaunching ?? – Ravi Ojha Dec 02 '15 at 05:18
-
1This doesn't work with plural items defined in Localizable.stringsdict. Any idea if there's a possible fix? – Mihai Fratu Dec 08 '15 at 23:37
-
1
-
If anyone is looking for a swift result, here is how to force locale without needing a re-launch: http://stackoverflow.com/a/38429383/1511877 – royherma Jul 18 '16 at 05:49
-
This is not working for localised UIImages. Is there any way to use localised images using NSBundle and that are reloaded dynamically without the need of killing your app? – dvp.petrov Jul 26 '16 at 08:52
-
This works. For beginners in swift, just create a bridging header for this and use. Works perfectly. – Harsha Aug 05 '16 at 05:43
-
@Gilad when I change it to other language at runtime in my app and go back to view controller .. nothing effects ...so any idea why is it so??? – Bhavin Bhadani Aug 15 '16 at 09:41
-
@EICaptainv2.0 : you need to reload the controller (check one of my previous comments explaining this issue). When you reload the controller - it will reload the view (from the new bundle) – Gilad Novik Aug 16 '16 at 16:29
-
@Gilad been banging my head against the wall all day. Yours seems like the way to go, but I am not getting my storyboard to load the localized storyboard. No matter what, it stays in the default language. I put a break in setLanguage does get called once in AppDelegate and once to change language before I load my storyboard. I also put a break in localizedStringForKey but it never gets called. Will this only work if my code manually calls localizeStringForKey? I was hoping this would work for the storyboard loading process itself. – Chuck Krutsinger Aug 17 '16 at 23:30
-
@ChuckKrutsinger you need to reload the storyboard (default template loads it once and save it to the app delegate) - you need to reload it after you change the language so it will use the new storyboard (with the right language). – Gilad Novik Aug 18 '16 at 08:21
-
@Gilad - Thanks for getting back. I was already changing the language prior to loading the Storyboard. Problem is that UIStoryboard does not call localizedStringForKey when loading those localized storyboards. It appears to call + storyboardWithName:bundle: passing in a bundle that contains the localized storyboard. I am going to use that mechanism to handle my situation as well. – Chuck Krutsinger Aug 18 '16 at 15:03
-
@Gilad - Figured out a simple way to accomplish what I needed based on extending your solution with one additional function: [UIStoryboard storyboardWithName:storyboardName bundle:[NSBundle localizedBundle]] using +(NSBundle *)localizedBundle { NSBundle* bundle=objc_getAssociatedObject([self mainBundle], &_bundle); return bundle ? bundle : [self mainBundle]; } The localized bundle has localized interface builder storyboards in it. – Chuck Krutsinger Aug 18 '16 at 22:48
-
-
@magid I first localized the storyboards using Interface Builder, but NOT Base localization. – Chuck Krutsinger Sep 09 '16 at 23:02
-
@magid I first localized the storyboards using Interface Builder, but NOT Base localization. When I programmatically launch the storyboard, I need to tell UIStoryboard to look in the localized bundle, which is pointed to by Gilad answer above for NSBundle+Language. The code to retrieve the localized storyboard is: UIStoryboard* aStoryboard = [UIStoryboard storyboardWithName:tStoryboardName bundle[NSBundle localizedBundle]] Hope that helps. – Chuck Krutsinger Sep 09 '16 at 23:11
-
I could not get this working.. Though I am settings setLanguage call in my main.m file.. – Ash Aug 09 '17 at 06:01
-
1couldn't get this to work on iOS 11. Anyone else facing the same issue ? – user3752049 Nov 03 '17 at 15:26
I usually do this in this way, but you MUST have all localization files in your project.
@implementation Language
static NSBundle *bundle = nil;
+(void)initialize
{
NSUserDefaults* defs = [NSUserDefaults standardUserDefaults];
NSArray* languages = [defs objectForKey:@"AppleLanguages"];
NSString *current = [[languages objectAtIndex:0] retain];
[self setLanguage:current];
}
/*
example calls:
[Language setLanguage:@"it"];
[Language setLanguage:@"de"];
*/
+(void)setLanguage:(NSString *)l
{
NSLog(@"preferredLang: %@", l);
NSString *path = [[ NSBundle mainBundle ] pathForResource:l ofType:@"lproj" ];
bundle = [[NSBundle bundleWithPath:path] retain];
}
+(NSString *)get:(NSString *)key alter:(NSString *)alternate
{
return [bundle localizedStringForKey:key value:alternate table:nil];
}
@end

- 1,493
- 1
- 12
- 21

- 1,941
- 1
- 12
- 12
-
Nice, works excellently. I changed the initialize method to just do bundle = [NSBundle mainBundle]; instead. That way, you don't need to have all localization files in your project. – quano Feb 22 '10 at 22:08
-
1+1. This is a really nice trick that I haven't seen anywhere else. By creating a "sub bundle" from one of the localization folders, you can get the string stuff to work fine as long as you wrap NSLocalizedString with something that detours here. – Ben Zotto Jun 28 '10 at 15:44
-
-
4Excellent Mauro. I noticed that it can also work for files out of your project. If for some reason (as in my case), you need to download strings files from network, and store them in your 'Documents' directory (with the folder structure Documents/en.lproj/Localizable.strings, Documents/fr.lproj/Localizable.strings, ...). You can even though make a NSBundle. Just use this code for path : NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"/Documents/%@.lproj", l, nil]]; – arnaud del. Feb 06 '12 at 21:13
-
1Seems to me that this is the best approach, along with the contribution from Alessandro below. It's not so intrusive and shouldn't require a restart. – PKCLsoft Feb 29 '12 at 03:37
-
1What am I doing wrong? I made a Language class, inheriting NSObject, put this in the implementation, put the method names in .h, then put [Language setLanguage:@"es"]; in my Change Language Button, code runs(button method gets called, and goes to Language class), but does nothing. I have my localizable.strings (Spanish) set up too. But it seems to be working for a lot of other people. Please someone dumb it down for me. – SirRupertIII Nov 19 '12 at 23:37
-
1@KKendall you call it like this: [Language setLanguage:@"es"]; NSString *stringToUse = [Language get:@"Your Text" alter:nil]; – Mikrasya Sep 28 '13 at 19:08
-
[related question](http://stackoverflow.com/questions/25398393/how-to-dynamically-switch-between-different-localized-storyboards-objective-c) basically how to do the same with localized storyboards – abbood Aug 20 '14 at 06:50
-
1This doesn't work with plural items defined in Localizable.stringsdict. Any idea if there's a possible fix? – Mihai Fratu Dec 08 '15 at 23:37
-
How to use it i dont understant or it not working in simulator – Mohammed Hussain Jan 25 '17 at 02:08
-
I have Localizable.string file , but still its not working on iOS 10.2 – Biranchi Feb 07 '17 at 12:36
Do not use on iOS 9. This returns nil for all strings passed through it.
I have found another solution that allows you to update the language strings, w/o restarting the app and compatible with genstrings:
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"];
Works even with consecutive language hopping like:
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, @""));

- 4,106
- 36
- 54

- 4,137
- 5
- 38
- 54
-
2@powerj1984: no, it will change only the strings in your source files. If you want to change the xib languages, you have to reload the xibs by hand, from the bundle of your selected language. – gklka Jan 23 '14 at 21:57
-
@gklka I have follow the steps given by Tudozier but my XIB's are not changing the language , as you told reload XIB by hand , what tis actually mean to reload XIBs ? – Dk Kumar Feb 22 '14 at 08:55
-
@DkKumar: You have to do something similar to this: http://stackoverflow.com/questions/21304988/reload-storyboard-to-change-locale/21322176#21322176 – gklka Feb 22 '14 at 12:12
-
@gklka Your answer seems to correct and i have did the same steps as you descried in your answer , but what is problem is if we change the bundle path than it will find all the resource (i.e. .png file used in XIB)in the same bundle , so we have to over copy the images folder in all the bundle like en.lproj, es.lproj and so on .. so will effect on increasing IPA size , so is there any way to overcome on this problem ? as you said in your post, let me try on this and let you more on this Thanks for helping me out for the same – Dk Kumar Feb 24 '14 at 03:51
-
@gklka I have checked it is working but there are 2 major problems #1 you have to initialize XIB every time #2 my IPA size in increased from 16.5-->195 MB this is large change i think because there are lots of images are there in my application – Dk Kumar Feb 24 '14 at 06:06
-
@DkKumar: yes, these side effects are known with this method. There is one more: you have to modify all of your Storyboards one by one if something changes. Please let me know, if you find anything better! – gklka Feb 24 '14 at 07:00
-
1This is horribly broken in iOS 9, returning the null for all strings. – Alex Zavatone Oct 14 '15 at 16:25
-
As said earlier, just do:
[[NSUserDefaults standardUserDefaults] setObject: [NSArray arrayWithObjects:@"el", nil] forKey:@"AppleLanguages"];
But to avoid having to restart the app, put the line in the main method of main.m
, just before UIApplicationMain
(...).

- 20,427
- 11
- 57
- 70

- 399
- 4
- 6
-
3Very helpful answer! P.S. May sound obvious to non-beginners, but you should insert that line after `NSAutoreleasePool * pool ..` or a few autoreleased objects will leak. – ySgPjx Jul 18 '11 at 16:52
-
1IMPORTANT: This won't work if you call `[[NSBundle mainBundle] URLForResource:withExtension:]` before. – Kof Jul 30 '13 at 08:31
-
3
-
-
Hi , How to localize dynamic text which is coming from server, in my application every text i have to display in simplified chinese language, But how to display the text in chinese which is coming in english. help me. – Mahesh Narla Mar 28 '17 at 06:02
-
I added this before `UIApplicationMain(argc` but still the language change only takes effect after restart. Any way to avoid this ? – user3752049 Jun 23 '17 at 12:44
The trick to use specific language by selecting it from the app is to force the NSLocalizedString
to use specific bundle depending on the selected language ,
here is the post i have written for this learning advance localization in ios apps
and here is the code of one sample app advance localization in ios apps
-
It works on iOS7 as well, I have to switch from Brian's solution to this as it seems like iOS overrides the languages option again thus I stuck with the first-time setting of language. Your solution works like a charm! – haxpor Dec 28 '13 at 12:59
What do you think about this solution for Swift 3?
extension String {
func localized(forLanguage language: String = Locale.preferredLanguages.first!.components(separatedBy: "-").first!) -> String {
guard let path = Bundle.main.path(forResource: language == "en" ? "Base" : language, ofType: "lproj") else {
let basePath = Bundle.main.path(forResource: "Base", ofType: "lproj")!
return Bundle(path: basePath)!.localizedString(forKey: self, value: "", table: nil)
}
return Bundle(path: path)!.localizedString(forKey: self, value: "", table: nil)
}
}
Simple usage:
"report".localized(forLanguage: "pl") //forced language
"report".localized() //default language selected by user in settings, in case when your app doesnt support selected lanaguage, the default one is selected, here is an english.

- 59,234
- 49
- 233
- 358
-
Hi , How to localize dynamic text which is coming from server, in my application every text i have to display in simplified chinese language, But how to display the text in chinese which is coming in english. help me. – Mahesh Narla Mar 28 '17 at 06:02
-
-
As Brian Webster mentions, the language needs to be set "sometime early in your application's startup". I thought applicationDidFinishLaunching:
of the AppDelegate
should be a suitable place to do it, since it's where I do all other initialization.
But as William Denniss mentions, that seems to have an effect only after the app is restarted, which is kind of useless.
It seems to work fine if I put the code in the main function, though:
int main(int argc, char *argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// Force language to Swedish.
[[NSUserDefaults standardUserDefaults]
setObject:[NSArray arrayWithObject:@"sv"]
forKey:@"AppleLanguages"];
int retVal = UIApplicationMain(argc, argv, nil, nil);
[pool release];
return retVal;
}
I'd appreciate any comments on this.

- 20,427
- 11
- 57
- 70

- 8,128
- 3
- 34
- 41
-
in my implementation it's a user-settable thing – so I just pop up a dialog telling them they'll need to restart :) – William Denniss Sep 04 '10 at 01:41
-
-
2If you're letting users set a language and then telling them to restart the app, just remember that the NSUserDefaults might not be saved if they restart too quickly. Most users aren't this fast, but when you're testing the app you might be too fast and see inconsistent behavior as a result. It took me a couple hours to realize why my language switch was sometimes working and sometimes not! – arlomedia Jan 04 '13 at 07:21
-
3That's not an issue, just use `[[NSUserDefaults standardUserDefaults] synchronize];` after calling `setObject:forKey:` – Ben Baron Feb 01 '13 at 01:38
NSLocalizedString()
reads the value for the key AppleLanguages
from the standard user defaults ([NSUserDefaults standardUserDefaults]
). It uses that value to choose an appropriate localization among all existing localizations at runtime. When Apple builds the user defaults dictionary at app launch, they look up the preferred language(s) key in the system preferences and copy the value from there. This also explains for example why changing the language settings in OS X has no effect on running apps, only on apps started thereafter. Once copied, the value is not updated just because the settings change. That's why iOS restarts all apps if you change then language.
However, all values of the user defaults dictionary can be overwritten by command line arguments. See NSUserDefaults
documentation on the NSArgumentDomain
. This even includes those values that are loaded from the app preferences (.plist) file. This is really good to know if you want to change a value just once for testing.
So if you want to change the language just for testing, you probably don't want to alter your code (if you forget to remove this code later on ...), instead tell Xcode to start your app with a command line parameters (e.g. use Spanish localization):
No need to touch your code at all. Just create different schemes for different languages and you can quickly start the app once in one language and once in another one by just switching the scheme.

- 125,244
- 33
- 244
- 253
-
It works only for 1st time after that it again loads into device pref. language .. – Ash Aug 01 '17 at 17:05
-
@Aks Works every time for me. Make sure you are starting the correct scheme, make sure you starting from within Xcode (relaunches, forks, etc. won't get the argument) and make sure that you don't override the language in `Options` as with newer Xcode versions Apple offers that as well. – Mecki Aug 02 '17 at 08:34
-
Thanks for your reply @Mecki.. For me its not working in xcode but when I mention in code, it work.. But still if I have set my device with some other preferred languages it needs to restart the app to load into my preferred language which I am passing in arguments.... – Ash Aug 02 '17 at 20:04
-
@Aks When using that on a device, it will only work when started directly from Xcode, it won't work when you start the app again by tapping its icon on some device and it will also not work when the app is killed (e.g. because it went to background) and gets restarted by the system (as this restart is not a restart done by Xcode) - so switching to a different app and back may not work if iOS has to kill your app in-between (e.g. because it needs the memory). – Mecki Aug 03 '17 at 15:14
-
You can combine this Argument pass with the change in StandardUserDefaults and it will work like a charm every time – L33MUR Jul 07 '20 at 23:17
I like best Mauro Delrio's method. I also have added the following in my Project_Prefix.pch
#import "Language.h"
#define MyLocalizedString(key, alt) [Language get:key alter:alt]
So if you ever want to use the standard method (that uses NSLocalizedString) you can make a quick syntax substitution in all files.

- 175
- 1
- 8
-
1I also like his method and I add a method to load png images: +(UIImage *)imageNamed:(NSString *)imageFileName{ NSString* fullPath = [bundle pathForResource:imageFileName ofType:@"png"]; UIImage* imageObj = [[UIImage alloc] initWithContentsOfFile:fullPath]; return [imageObj autorelease]; } – Jagie Jul 11 '11 at 13:04
I came up with a solution that allows you to use NSLocalizedString
. I create a category of NSBundle
call NSBundle+RunTimeLanguage
. The interface is like this.
// NSBundle+RunTimeLanguage.h
#import <Foundation/Foundation.h>
@interface NSBundle (RunTimeLanguage)
#define NSLocalizedString(key, comment) [[NSBundle mainBundle] runTimeLocalizedStringForKey:(key) value:@"" table:nil]
- (NSString *)runTimeLocalizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName;
@end
The implementation is like this.
// NSBundle+RunTimeLanguage.m
#import "NSBundle+RunTimeLanguage.h"
#import "AppDelegate.h"
@implementation NSBundle (RunTimeLanguage)
- (NSString *)runTimeLocalizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName
{
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
NSString *path= [[NSBundle mainBundle] pathForResource:[appDelegate languageCode] ofType:@"lproj"];
NSBundle *languageBundle = [NSBundle bundleWithPath:path];
NSString *localizedString=[languageBundle localizedStringForKey:key value:key table:nil];
return localizedString;
}
@end
Than just add import NSBundle+RunTimeLanguage.h
into the files that use NSLocalizedString
.
As you can see I store my languageCode in a property of AppDelegate
. This could be stored anywhere you'd like.
This only thing I don't like about it is a Warning that NSLocalizedString
marco redefined. Perhaps someone could help me fix this part.
-
1Add `#undef NSLocalizedString` just before `#define` to disable the warning – beryllium May 03 '14 at 19:02
-
Does this work on localization for xib file ? I have .xib file and .strings to translate UIs name in particular language. I tried and it does not work with XIB but I am not sure if I have done things correctly – Kong Hantrakool Mar 01 '15 at 18:18
-
Kong sorry for the delayed response. This works where ever you use NSLocalizedString. So it will not work directly in an XIB. You would need IBOutlets to the strings in the XIB and then would have to programmatically set the string values in code. – qman64 Oct 12 '15 at 23:29
-
This approach worked for me and I was able to changes languages on-the-fly. Note that language codes like "es", fr" and "en" worked fine. But "zh" (for Simplified Chinese) failed and gave me null strings back. I did a global search on my system for "es.lproj" to see where the files I was accessing were and I discovered there that "zh.lproj" is actually "zh-Hans.lproj". – Gallymon Jul 23 '18 at 02:46
Swift 3 extensions:
extension Locale {
static var preferredLanguage: String {
get {
return self.preferredLanguages.first ?? "en"
}
set {
UserDefaults.standard.set([newValue], forKey: "AppleLanguages")
UserDefaults.standard.synchronize()
}
}
}
extension String {
var localized: String {
var result: String
let languageCode = Locale.preferredLanguage //en-US
var path = Bundle.main.path(forResource: languageCode, ofType: "lproj")
if path == nil, let hyphenRange = languageCode.range(of: "-") {
let languageCodeShort = languageCode.substring(to: hyphenRange.lowerBound) // en
path = Bundle.main.path(forResource: languageCodeShort, ofType: "lproj")
}
if let path = path, let locBundle = Bundle(path: path) {
result = locBundle.localizedString(forKey: self, value: nil, table: nil)
} else {
result = NSLocalizedString(self, comment: "")
}
return result
}
}
Usage:
Locale.preferredLanguage = "uk"
label.text = "localizedKey".localized

- 10,031
- 5
- 63
- 86
-
-
Yes it is working but app needs to restart to change language. – Hasan Can Gunes Feb 27 '21 at 09:22
In swift 4, I have solved it without needing to restart or use libraries.
After trying many options, I found this function, where you pass the stringToLocalize (of Localizable.String, the strings file) that you want to translate, and the language in which you want to translate it, and what it returns is the value for that String that you have in Strings file:
func localizeString (stringToLocalize: String, language: String) -> String
{
let path = Bundle.main.path (forResource: language, ofType: "lproj")
let languageBundle = Bundle (path: path!)
return languageBundle! .localizedString (forKey: stringToLocalize, value: "", table: nil)
}
Taking into account this function, I created this function in a Swift file:
struct CustomLanguage {
func createBundlePath () -> Bundle {
let selectedLanguage = //recover the language chosen by the user (in my case, from UserDefaults)
let path = Bundle.main.path(forResource: selectedLanguage, ofType: "lproj")
return Bundle(path: path!)!
}
}
To access from the whole app, and in each string of the rest of ViewControllers, instead of putting:
NSLocalizedString ("StringToLocalize", comment: “")
I have replaced it with
let customLang = CustomLanguage() //declare at top
let bundleLanguage = customLang.createBundle()
NSLocalizedString("StringToLocalize", tableName: nil, bundle: bundleLanguage, value: "", comment: “”) //use in each String
I do not know if it's the best way, but I found it very simple, and it works for me, I hope it helps you!

- 16,698
- 6
- 112
- 113

- 149
- 1
- 6
-
This answer is great because it also works in a Swift Package running on Linux for example. – Rémi B. Sep 30 '20 at 18:11
In a nutshell :
Localize your application
It's the first thing you have to do is to localise your app with at least two languages (english and french in this example).
Override NSLocalizedString
In your code, instead of using NSLocalizedString(key, comment)
, use a macro MYLocalizedString(key, comment)
defined like this :
#define MYLocalizedString(key, comment) [[MYLocalizationSystem sharedInstance] localizedStringForKey:(key) value:(comment)];
This MYLocalizationSystem
singleton will :
- Set langage by setting the right localized NSBundle user asks for
- Returns the localized NSString according to this previously set language
Set user language
When user changed application language in french, call [[MYLocalizationSystem sharedInstance] setLanguage:@"fr"];
- (void)setLanguage:(NSString *)lang
{
NSString *path = [[NSBundle mainBundle] pathForResource:lang ofType:@"lproj"];
if (!path)
{
_bundle = [NSBundle mainBundle];
NSLog(@"Warning: No lproj for %@, system default set instead !", lang);
return;
}
_bundle = [NSBundle bundleWithPath:path];
}
In this example this method set localized bundle to fr.lproj
Return localized string
Once you've set the localized bundle, you'll be able to get the right localised string from him with this method :
- (NSString *)localizedStringForKey:(NSString *)key value:(NSString *)value
{
// bundle was initialized with [NSBundle mainBundle] as default and modified in setLanguage method
return [self.bundle localizedStringForKey:key value:value table:nil];
}
Hope this will help you.
You'll find more details in this article from NSWinery.io

- 241
- 4
- 4
-
We ask that you not just link to a solution in your answer; the link might stop working some day. While you don't have to remove the link from your answer, we do ask that you edit your answer to include a summary of the relevant section of the linked article. – Oblivious Sage Apr 22 '15 at 18:51
In file .pch to define:
#define currentLanguageBundle [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[[NSLocale preferredLanguages] objectAtIndex:0] ofType:@"lproj"]]
#define NSLocalizedString(str,nil) NSLocalizedStringFromTableInBundle(str, nil, currentLanguageBundle, @"")
-
-
1Simple solution does everything I need. Was able to use this as a guide to solve my problem. If pathForResource returns nil because I don't have a localization file then I use pathForResource:@"Base" since nothing else I have tried pulls strings from the base localization. Thank you. – GRW Sep 19 '14 at 05:44
-
This is hacky (so are all the other answers), and it was easiest to implement in the unit test I was writing. – Max Dec 11 '19 at 17:23
Swift 3 solution:
let languages = ["bs", "zh-Hant", "en", "fi", "ko", "lv", "ms", "pl", "pt-BR", "ru", "sr-Latn", "sk", "es", "tr"]
UserDefaults.standard.set([languages[0]], forKey: "AppleLanguages")
Gave some examples of language codes that can be used. Hope this helps

- 382
- 1
- 6
- 14
Maybe you should complement with this (on .pch file after #import ):
extern NSBundle* bundle; // Declared on Language.m
#ifdef NSLocalizedString
#undef NSLocalizedString
// Delete this line to avoid warning
#warning "Undefining NSLocalizedString"
#endif
#define NSLocalizedString(key, comment) \
[bundle localizedStringForKey:(key) value:@"" table:nil]

- 1,493
- 1
- 12
- 21

- 2,030
- 16
- 20
-
/Users/pwang/Desktop/Myshinesvn/Myshine/viewController/OrientationReadyPagesView.m:193:31: Use of undeclared identifier 'bundle' – pengwang Mar 12 '13 at 04:08
You could build a sub-bundle with the set of localized strings that you want to do this with, and then use NSLocalizedStringFromTableInBundle()
to load them. (I'm assuming that this is content separate from the normal UI localization you might be doing on the app.)

- 14,816
- 3
- 48
- 60
for my case i have two localized file , ja and en
and i would like to force it to en if the preferred language in the system neither en or ja
i'm going to edit the main.m file
i 'll check whether the first preferred is en or ja , if not then i 'll change the second preferred language to en.
int main(int argc, char *argv[])
{
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize];
NSString *lang = [[NSLocale preferredLanguages] objectAtIndex:0];
if (![lang isEqualToString:@"en"] && ![lang isEqualToString:@"ja"]){
NSMutableArray *array = [[NSMutableArray alloc] initWithArray:[NSLocale preferredLanguages]];
[array replaceObjectAtIndex:1 withObject:@"en"];
[[NSUserDefaults standardUserDefaults] setObject:array forKey:@"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

- 1,859
- 24
- 24
-
Thanks @chings228 it is usefull for me, but this not change the default launch image (splash) for the app I have diferents splashs for each language. do you know how to apply for this?? – JERC Jun 04 '14 at 18:13
-
i think the splash runs before the main program start to run , so i don't know how to override it , may be plist can help but it may work for next time the app opens – chings228 Jun 05 '14 at 01:12
You can do something like this:
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"Localizable" ofType:@"strings" inDirectory:nil forLocalization:@"es"];
NSBundle *spanishBundle = [[NSBundle alloc] initWithPath:[bundlePath stringByDeletingLastPathComponent]];
NSLocalizedStringFromTableInBundle(@"House", nil, spanishBundle, nil):

- 1,584
- 3
- 17
- 38
Here is a decent solution for this problem, and it does not require application restart.
https://github.com/cmaftuleac/BundleLocalization
This implementation works by tweaking inside NSBundle. The idea is that you override the method localizedStringForKey on the instance of NSBundle object, and then call this method on a different bundle with a different language. Simple and elegant fully compatible with all types of resources.

- 438
- 4
- 14
-
This code from the project helped me a lot. How to find a bundle for specific language code --- `NSString *path = [[NSBundle mainBundle] pathForResource:lang ofType:@"lproj" ];` – eonil Apr 12 '16 at 09:26
-
This class is working fine, but after changing language to another, its not effecting. – Anilkumar iOS - ReactNative Aug 04 '16 at 07:09
Based on Tudorizer's answer to change language without leaving or restarting the application.
Instead of a macro, use a class for accessing the preferred language in order to check if a specific language code is present.
Below is a class used to obtain the current language bundle that is working for iOS 9:
@implementation OSLocalization
+ (NSBundle *)currentLanguageBundle
{
// Default language incase an unsupported language is found
NSString *language = @"en";
if ([NSLocale preferredLanguages].count) {
// Check first object to be of type "en","es" etc
// Codes seen by my eyes: "en-US","en","es-US","es" etc
NSString *letterCode = [[NSLocale preferredLanguages] objectAtIndex:0];
if ([letterCode rangeOfString:@"en"].location != NSNotFound) {
// English
language = @"en";
} else if ([letterCode rangeOfString:@"es"].location != NSNotFound) {
// Spanish
language = @"es";
} else if ([letterCode rangeOfString:@"fr"].location != NSNotFound) {
// French
language = @"fr";
} // Add more if needed
}
return [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:language ofType:@"lproj"]];
}
/// Check if preferred language is English
+ (BOOL)isCurrentLanguageEnglish
{
if (![NSLocale preferredLanguages].count) {
// Just incase check for no items in array
return YES;
}
if ([[[NSLocale preferredLanguages] objectAtIndex:0] rangeOfString:@"en"].location == NSNotFound) {
// No letter code for english found
return NO;
} else {
// Tis English
return YES;
}
}
/* Swap language between English & Spanish
* Could send a string argument to directly pass the new language
*/
+ (void)changeCurrentLanguage
{
if ([self isCurrentLanguageEnglish]) {
[[NSUserDefaults standardUserDefaults] setObject:@[@"es"] forKey:@"AppleLanguages"];
} else {
[[NSUserDefaults standardUserDefaults] setObject:@[@"en"] forKey:@"AppleLanguages"];
}
}
@end
Use the class above to reference a string file / image / video / etc:
// Access a localized image
[[OSLocalization currentLanguageBundle] pathForResource:@"my_image_name.png" ofType:nil]
// Access a localized string from Localizable.strings file
NSLocalizedStringFromTableInBundle(@"StringKey", nil, [OSLocalization currentLanguageBundle], @"comment")
Change language in-line like below or update the "changeCurrentLanguage" method in the class above to take a string parameter referencing the new language.
[[NSUserDefaults standardUserDefaults] setObject:@[@"es"] forKey:@"AppleLanguages"];

- 578
- 1
- 5
- 15
This function will try to get localized string for current language and if it's not found it will get it using english language.
- (NSString*)L:(NSString*)key
{
static NSString* valueNotFound = @"VALUE_NOT_FOUND";
static NSBundle* enBundle = nil;
NSString* pl = [NSLocale preferredLanguages][0];
NSString* bp = [[NSBundle mainBundle] pathForResource:pl ofType:@"lproj"];
NSBundle* b = [NSBundle bundleWithPath:bp];
NSString* s = [b localizedStringForKey:key value:valueNotFound table:nil];
if ( [s isEqualToString:valueNotFound] ) {
if ( !enBundle ) {
bp = [[NSBundle mainBundle] pathForResource:@"en" ofType:@"lproj"];
enBundle = [NSBundle bundleWithPath:bp];
}
s = [enBundle localizedStringForKey:key value:key table:nil];
}
return s;
}

- 2,659
- 22
- 29
I wanted to add support for a language that isn't officially supported by iOS (not listed in Language section under system settings). By following the Apple's Internationalization Tutorial and few hints here by Brian Webster and geon, I came up with this piece of code (put it in main.m):
int main(int argc, char * argv[]) {
@autoreleasepool {
// Grab regional settings locale, for Slovenian this is either sl_SI or en_SI
NSLocale *locale = [NSLocale currentLocale];
NSString *ll = [locale localeIdentifier]; // sl_SI
// Grab the first part of language identifier
NSArray *comp = [ll componentsSeparatedByString:@"_"];
NSString *ll1 = @"en";
if (comp.count > 0) {
ll1 = comp[0]; // sl, en, ...
}
// Check if we already saved language (user can manually change it inside app for example)
if (![[NSUserDefaults standardUserDefaults] objectForKey:@"SelectedLanguage"]) {
// Slovenian (Slovenia), Slovenia
if ([ll isEqualToString:@"sl_SI"] || [ll isEqualToString:@"en_SI"]) {
ll1 = @"sl-SI"; // This is the part of localized path for Slovenian language that Xcode generates
}
// Add more unsupported languages here...
[[NSUserDefaults standardUserDefaults] setObject:ll1 forKey:@"SelectedLanguage"]; // Save language
}
else {
// Restore language as we have previously saved it
ll1 = [[NSUserDefaults standardUserDefaults] objectForKey:@"SelectedLanguage"];
}
// Overwrite NSLocalizedString and StoryBoard language preference
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:ll1, @"en", @"fr", nil] forKey:@"AppleLanguages"];
// Make sure settings are stored to disk
[[NSUserDefaults standardUserDefaults] synchronize];
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
This works well for both Storyboard and NSLocalizedString code. The code assumes that user will have an option to manually change language inside app later on.
Of course, don't forget to add proper Storyboard translations and Localizable.strings translations (see link to Apple page above for how to do that).

- 4,474
- 3
- 31
- 23
-
I see you are also facing problems with Slovenian language :) To improve this answer for languages not supported by iOS, have you figured out if we can set custom localizable strings which will be used for system controls in app (Edit, Done, More,...)? – miham Jul 18 '16 at 11:40
For Swift you can override the main.swift
file and set the UserDefaults string there before you app runs. This way you do not have to restart the App to see the desired effect.
import Foundation
import UIKit
// Your initialisation code here
let langCultureCode: String = "LANGUAGE_CODE"
UserDefaults.standard.set([langCultureCode], forKey: "AppleLanguages")
UserDefaults.standard.synchronize()
UIApplicationMain(CommandLine.argc, CommandLine.unsafeArgv, nil, NSStringFromClass(AppDelegate.self))
paired together with the removal of @UIApplicationMain
in your AppDelegate.swift
file.

- 656
- 9
- 7
For me, Test-Plan user, specifying -AppleLanguages (en_BZ)
(English Belize) in the TestPlan's Arguments Passed On Launch
is working.
Since we use en_GB and en_BZ, iOS always preferred en_GB. Even so when I switched the devices language to EN and the region to BZ and when setting these values in the Test Plans Application Language
and Application Region
settings . Nothing helped except the good old arguments approach above :)

- 9,011
- 7
- 45
- 56
whatever you all do, the best way is to take the short_name for the specified language, i.e.: fr, en, nl, de, it, etc... and assign the same to a global value.
make a picker view to pop up like a drop down menu (combination of a button on click of which a picker view appears from below with a list of languages) and select the language you desire. let the short name be stored internally. make a .h + .m file named LocalisedString.
Set the global value of short_name to be equal to the obtained value in LocalisedString.m When the required language is selected assign the NSBundlePath to create project sub-directories for the needed language. for eg, nl.proj, en.proj.
When the particular proj folder is selected call the localised string for the respective language and change the language dynamically.
no rules broken.

- 63
- 2
- 8