Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Localization on the fly with localized Storyboards

I'm working on an app that has a toggle button to switch between English and Arabic language and should be on the fly. I'm using the method in https://github.com/maximbilan/ios_language_manager and it works fine in all cases except if the storyboard is localized by interface not strings:

enter image description here

Now when I reload the root view controller like this:

   func reloadRootVC(){

    let delegate : AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate

    let storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())

    delegate.window?.rootViewController = (storyboard.instantiateInitialViewController())
}

it reload the root with localized strings and in RTL but with the english storyboard not the arabic one.

Tried force loading the arabic one like this:

let storyboard = UIStoryboard(name: "Main", bundle: NSBundle(path: NSBundle.mainBundle().pathForResource(LanguageManager.currentLanguageCode(), ofType: "lproj")!))

but unfortunately it loads the storyboard but with no images. It can't read any resource image.

like image 466
Hossam Ghareeb Avatar asked May 03 '16 13:05

Hossam Ghareeb


People also ask

How do I localize Xib files?

strings files from the xib, which make localization pretty straight forward. Right click on the xib file in Xcode, and choose Get Info . Select the General tab and on the bottom click Make File Localizable . Then you will be able to add localizations by clicking Add Localization on that same tab.

What is localized in Swift?

Localization is the process of making your app support other languages. In many cases, you make your app with English user interface first and then localize the app to other languages such as Japanese. The process of localization is tedious, and steps of it change little by little as XCode gets updated.


2 Answers

I ended up by moving the arabic storyboard outside and name it Main-AR, then adding an extension in UIStoryboard to swizzle and initializer of storyboard to add -AR to the end of the storyboard name if i'm on arabic mode.

extension UIStoryboard {
public override class func initialize() {
    struct Static {
        static var token: dispatch_once_t = 0
    }

    // make sure this isn't a subclass
    if self !== UIStoryboard.self {
        return
    }

    dispatch_once(&Static.token) {
        let originalSelector = #selector(UIStoryboard.init(name:bundle:))
        let swizzledSelector = #selector(UIStoryboard.initWithLoc(_:bundle:))

        let originalMethod = class_getClassMethod(self, originalSelector)
        let swizzledMethod = class_getClassMethod(self, swizzledSelector)

        class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))

        method_exchangeImplementations(originalMethod, swizzledMethod)

    }
}

// MARK: - Method Swizzling

class func initWithLoc(name: String, bundle storyboardBundleOrNil: NSBundle?) -> UIStoryboard{
    var newName = name
    if LanguageManager.isCurrentLanguageRTL(){
        newName += "-AR"
        if #available(iOS 9.0, *) {
            UIView.appearance().semanticContentAttribute = .ForceRightToLeft
        } else {
            // Fallback on earlier versions

        }
    }
    else{
        if #available(iOS 9.0, *) {
            UIView.appearance().semanticContentAttribute = .ForceLeftToRight
        } else {
            // Fallback on earlier versions
        }
    }
    return initWithLoc(newName, bundle: storyboardBundleOrNil)
}
}
like image 74
Hossam Ghareeb Avatar answered Nov 15 '22 00:11

Hossam Ghareeb


change the bundle which is used to init the storyboard:

        let path = Bundle.main.path(forResource: "ar", ofType: "lproj")
        let bundle = Bundle(path: path!)
        let delegate : AppDelegate = UIApplication.shared.delegate as! AppDelegate
        let storyboard = UIStoryboard(name: "Main", bundle: bundle)
        delegate.window?.rootViewController = (storyboard.instantiateInitialViewController())

although this change the storyboard based on language but do not load images! :(

like image 22
Navid Avatar answered Nov 14 '22 23:11

Navid