You want to set the language of the app from the app UI ignoring the user preference on the device. This is unusual, but here you go...
First write all your language strings on a directory structure like this:
i18n/en.lproj/Localizable.strings
i18n/ar.lproj/Localizable.strings
Create an additional directory with the corresponding two letter code for each additional language supported.
If the files are recognized as i18n resources, they will be presented like this:
Files will have a key=value with the following format:
"button.back" = "???";
In your code, replace any localizable string with the key. Example:
[self.stateBtn setTitle:localize(@"button.back") forState:UIControlStateNormal];
Usually you would use NSLocalizedString(@"key",@"fallback")
but since you want to ignore iPhone settings, I wrote a localize(@"key")
macro above that will have the following implementation:
Localization.h
#ifndef localize
#define localize(key) [[Localization sharedInstance] localizedStringForKey:key]
#endif
@interface Localization : NSObject
@property (nonatomic, retain) NSBundle* fallbackBundle;
@property (nonatomic, retain) NSBundle* preferredBundle;
@property (nonatomic, copy) NSString* fallbackLanguage;
@property (nonatomic, copy) NSString* preferredLanguage;
-(NSString*) localizedStringForKey:(NSString*)key;
-(NSString*) pathForFilename:(NSString*)filename type:(NSString*)type;
+(Localization*)sharedInstance;
@end
Localization.m
#import "Localization.h"
@implementation Localization
+(Localization *)sharedInstance
{
static dispatch_once_t pred;
static Localization *shared = nil;
dispatch_once(&pred, ^{
shared = [[Localization alloc] init];
[shared setPreferred:@"en" fallback:@"ar"];
});
return shared;
}
-(void) setPreferred:(NSString*)preferred fallback:(NSString*)fallback
{
self.fallbackLanguage = fallback;
self.preferredLanguage = preferred;
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"Localizable" ofType:@"strings" inDirectory:nil forLocalization:self.fallbackLanguage];
self.fallbackBundle = [[NSBundle alloc] initWithPath:[bundlePath stringByDeletingLastPathComponent]];
bundlePath = [[NSBundle mainBundle] pathForResource:@"Localizable" ofType:@"strings" inDirectory:nil forLocalization:self.preferredLanguage];
self.preferredBundle = [[NSBundle alloc] initWithPath:[bundlePath stringByDeletingLastPathComponent]];
}
-(NSString*) pathForFilename:(NSString*)filename type:(NSString*)type
{
NSString *path = [self.preferredBundle pathForResource:filename ofType:type inDirectory:nil forLocalization:self.preferredLanguage];
if (!path) path = [self.fallbackBundle pathForResource:filename ofType:type inDirectory:nil forLocalization:self.fallbackLanguage];
if (!path) NSLog(@"Missing file: %@.%@", filename, type);
return path;
}
-(NSString*) localizedStringForKey:(NSString*)key
{
NSString* result = nil;
if (_preferredBundle!=nil) {
result = [_preferredBundle localizedStringForKey:key value:nil table:nil];
}
if (result == nil) {
result = [_fallbackBundle localizedStringForKey:key value:nil table:nil];
}
if (result == nil) {
result = key;
}
return result;
}
@end
This will use lookup the key strings in the arabic file, and if the key is missing, it will look in the arabic file. If you want it the other way, do the following from your button handlers:
[[Localization sharedInstance] setPreferred:@"ar" fallback:@"en"];
Sample project at Github.
If localisation doesn't work
If localisation doesn't work, use the plutil command line tool to verify the format of the file. It should output: Localizable.strings: OK
. Example:
$ plutil -lint Localizable.strings
Localizable.strings: OK
This format is described in Internationalization Programming Topics > Localizing String Resources. You can optionally add // single-line
or /* multi-line */
comments. For non latin languages it’s recommended to encode Localized.strings in UTF-16. You can convert between encodings in the inspector pane of XCode.
If it still doesn't work, check that you are copying the Localizable.strings file in the Copy files phase of your target. Note that when you add Localizable.strings files there, sometimes they appear in red, keep doing it until a file appears in black, then delete the red ones (hacky I know, blame Xcode).