dsgriffin
dsgriffin

Reputation: 68596

Localize an iOS app inside application dynamically?

Currently, I have three separate .strings files - for English, French and German respectively.

I have a UISegmentedControl in the preferences section, where I would like to change the default .strings file used depending on which segment is selected.

enter image description here

Localisation is already working outside the application when I test it, and I've even managed to localise individual objects depending on which segment is selected (If france is selected, the label text below changes from "South" to "Sud", and then back again if English is re-selected) using this:

if(German segment) {
   NSString *path= [[NSBundle mainBundle] pathForResource:@"de" ofType:@"lproj"];
   NSBundle* languageBundle = [NSBundle bundleWithPath:path];

    // Returns german version of localised string as label text.
    self.defaultName.titleLabel.text = [languageBundle localizedStringForKey:@"PREF_WEATHER_NORTH" value:@"" table:nil]; 

    // I would like to set the default .strings file to 'de' here.
}

else if(French segment) {
   NSString *path= [[NSBundle mainBundle] pathForResource:@"fr" ofType:@"lproj"];
   NSBundle* languageBundle = [NSBundle bundleWithPath:path];

   // Returns french version of localised string as label text
   self.defaultName.titleLabel.text = [languageBundle localizedStringForKey:@"PREF_WEATHER_NORTH" value:@"" table:nil]; 

   // I would like to set the default .strings file to 'fr' here
}

else if(British segment) {
   NSString *path= [[NSBundle mainBundle] pathForResource:@"en" ofType:@"lproj"];
   NSBundle* languageBundle = [NSBundle bundleWithPath:path];

    // Returns english version of localised string as label text
    self.defaultName.titleLabel.text = [languageBundle localizedStringForKey:@"PREF_WEATHER_NORTH" value:@"" table:nil]; 

    // I would like to set the default .strings file to 'en' here.
}

Now, as I've already got individual strings being localised on button click, I was wondering if I could localise ALL strings in each of the .strings files in one go (so that I'm changing the default .strings used depending on which segment is selected) or at least target as many as possible in an acceptable amount of code.

Obviously, at the moment I could type them one-by-one, but that isn't really an option due to the amount of localised strings used in an application.

Any help would be appreciated.

Upvotes: 1

Views: 4009

Answers (2)

Mikhail
Mikhail

Reputation: 4311

You can wrap this localization approach in LocalizationSystem class:

@interface PLLocalizationSystem : NSObject

@property (strong, nonatomic) NSString *language;

+ (PLLocalizationSystem *) sharedLocalizationSystem;
- (NSString *) localizedStringForKey:(NSString *)key value:(NSString *)comment;

@end

@implementation PLLocalizationSystem {
    NSBundle *_bundle;
}


- (NSString *)localizedStringForKey:(NSString *)key value:(NSString *)comment {
    return [_bundle localizedStringForKey:key value:comment table:nil];
}

- (void)setLanguage:(NSString *)newLanguage {
    ...
    NSString *path = [[NSBundle mainBundle] pathForResource:newLanguage ofType:@"lproj"];
    if (path) {
        _bundle = [NSBundle bundleWithPath:path];
        _language = newLanguage;
    } else {
        [self resetLocalization];
    }
    ...
    [[NSNotificationCenter defaultCenter] postNotificationName:kLocalizationChangedNotification object:nil];
}

And make some defines for more simpler access (define in LocalizationSystem header file):

#define PLLocalizedString(key, comment) \
[[PLLocalizationSystem sharedLocalizationSystem] localizedStringForKey:(key) value:(comment)]

#define PLLocalizationSetLanguage(language) \
[[PLLocalizationSystem sharedLocalizationSystem] setLanguage:(language)]

#define PLLocalizationGetLanguage \
[[PLLocalizationSystem sharedLocalizationSystem] language]

Also you can import this file from your AppName-Prefix.pch file to get access from anywhere.

Next in your controllers you can observe for localization changes and call appropriate method.

So for now, you can use it in the same way as NSLocalizedString.

P.S. i'm not write here all implementation, but if somebody wants i may later share it on githab

Update. Usage sample.

For example, you have UIViewController which you want to localize dynamically:

@implementation MyCustomViewController

- (void)viewDidLoad {
   [super viewDidLoad];
   //first of all - register for localization changes
   //i made for this purposes category for UIViewController(localizable)
   [[NSNotificationCenter defaultCenter] addObserver:self
                                            selector:@selector(localize)
                                                name:kLocalizationChangedNotification
                                              object:nil];
}

//here you should apply all localization
- (void)localize {
    [self setTitle:PLLocalizedString(@"myTitle", nil);
    [label setText:PLLocalizedString(@"labelTitle", nil)];
    ....
}

@end

And in your preferences, when you change language call PLLocalizationSetLanguage(language), and all controllers registered for this event will be localized automatically. Of course, this approach needs that all localization applies in localize method.

And don't forgot to remove observer when controller dealloced or unloaded

Upvotes: 2

Tjirp
Tjirp

Reputation: 2455

You can read: How to force NSLocalizedString to use a specific language and http://aggressive-mediocrity.blogspot.nl/2010/03/custom-localization-system-for-your.html to see how you could do it (the 2nd one is more suited for what you want).

But read this (also from the second link):

In general, you should not change the iOS system language (via use of the AppleLanguages pref key) from within your application. This goes against the basic iOS user model for switching languages in the Settings app, and also uses a preference key that is not documented, meaning that at some point in the future, the key name could change, which would break your application.

If you want to switch languages in your application, you can do so via manually loading resource files in your bundle. You can use NSBundle:pathForResource:ofType:inDirectory:forLocalization: for this purpose, but keep in mind that your application would be responsible for all loading of localized data.

Upvotes: 0

Related Questions