iOS Language Manager
Switch branches/tags
Nothing to show
Clone or download
maximbilan Merge pull request #18 from alirp88/master
Problem with TableView in iOS 11
Latest commit 7e39200 Oct 31, 2017
Permalink
Failed to load latest commit information.
img Added screenshot Jan 27, 2015
ios_language_manager.xcodeproj Problem with TableView fix Oct 31, 2017
ios_language_manager Problem with TableView fix Oct 31, 2017
.gitignore Initial commit Dec 23, 2014
LICENSE Initial commit Dec 23, 2014
README.md Update README.md Sep 23, 2017

README.md

How to change localization internally in your iOS application

Unfortunately, there’s no official way provided by Apple for this purpose. Let’s look at two methods for solving this problem.

Method #1

Apple provides a way to specify an application-specific language, by updating the “AppleLanguages” key in NSUserDefaults. For example:

[[NSUserDefaults standardUserDefaults] setObject:@"fr" forKey:@"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize];

For working this method, you’ll have to set it before UIKit initialized.

//
//  main.m
//  ios_language_manager
//
//  Created by Maxim Bilan on 12/23/14.
//  Copyright (c) 2014 Maxim Bilan. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "LanguageManager.h"

int main(int argc, char * argv[]) {
    @autoreleasepool {
        [[NSUserDefaults standardUserDefaults] setObject:@"fr" forKey:@"AppleLanguages"];
        [[NSUserDefaults standardUserDefaults] synchronize];
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

The problem of this method is that the app has to be relaunched to take effect.

Method #2

The solution is to swap the mainBundle of our application as soon as the user changes their language preferences inside the app.

See the category for NSBundle.

Header:

#import <Foundation/Foundation.h>

@interface NSBundle (Language)

+ (void)setLanguage:(NSString *)language;

@end

Implementation:

#import "NSBundle+Language.h"
#import <objc/runtime.h>

static const char kBundleKey = 0;

@interface BundleEx : NSBundle

@end

@implementation BundleEx

- (NSString *)localizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName
{
    NSBundle *bundle = objc_getAssociatedObject(self, &kBundleKey);
    if (bundle) {
        return [bundle localizedStringForKey:key value:value table:tableName];
    }
    else {
        return [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]);
    });
    id value = language ? [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:language ofType:@"lproj"]] : nil;
    objc_setAssociatedObject([NSBundle mainBundle], &kBundleKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

@end

In this method, a problem that may arise is updating elements on active screens. You can reload your rootViewController from our application delegate, will always work reliably.

- (void)reloadRootViewController
{
    AppDelegate *delegate = [UIApplication sharedApplication].delegate;
    NSString *storyboardName = @"Main";
    UIStoryboard *storybaord = [UIStoryboard storyboardWithName:storyboardName bundle:nil];
    delegate.window.rootViewController = [storybaord instantiateInitialViewController];
}

All code you can see in this repository. With simple example.

alt tag

Please, use for free and like it ☺.

Note: In example project by default the app uses method #2. You can disable this. Just comment define USE_ON_FLY_LOCALIZATION.

More details on the blog here.