Локализация Swizzling смена языков swift4 с помощью селектора - PullRequest
0 голосов
/ 25 мая 2018

Я пытаюсь изменить язык приложения и использую функцию Swizzling, но проблема при вызове DoTheSwizzling () вылетает в селекторе!Я думаю, что не могу найти "specialLocalizedStringForKey", поэтому он дает мне ноль, я не знаю, что не так?

 class Languages {

        class func DoTheSwizzling() {

            MethodSwizzleGivenClassName(cls: Bundle.self, originalSelector: #selector(Bundle.localizedString(forKey:value:table:)), overrideSelector: Selector(("specialLocalizedStringForKey:value:table:")))
        }
    }

    extension Bundle {
        func specialLocalizedStringForKey(key: String, value: String?, table tableName: String?) -> String {
            let currentLanguage = Languages.currentAppleLanguage()
            var bundle = Bundle();
            if let _path = Bundle.main.path(forResource: currentLanguage, ofType: "lproj") {
                bundle = Bundle(path: _path)!
            } else {
                let _path = Bundle.main.path(forResource: "Base", ofType: "lproj")!
                bundle = Bundle(path: _path)!
            }
            return (bundle.specialLocalizedStringForKey(key: key, value: value, table: tableName))
        }
    }


    func MethodSwizzleGivenClassName(cls: AnyClass, originalSelector: Selector, overrideSelector: Selector) {

        let origMethod: Method = class_getInstanceMethod(cls, originalSelector)!;
        let overrideMethod: Method = class_getInstanceMethod(cls, overrideSelector)!;

        if (class_addMethod(cls, originalSelector, method_getImplementation(overrideMethod), method_getTypeEncoding(overrideMethod))) {
            class_replaceMethod(cls, overrideSelector, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
        } else {
            method_exchangeImplementations(origMethod, overrideMethod);
        }
    }

enter image description here

Ответы [ 3 ]

0 голосов
/ 25 мая 2018

Localizable.strings (английский)

"Home" = "Home";

Localizable.strings (арабский)

"Home" = "Home Arabic";

Ваше имя класса NSObject для EX: LanguageFile

 var home = "Home".localized(lang:"Your language")//en , ar

Расширение вашей строки

extension String {
  func localized(lang:String) ->String {
    //print(lang)
    let path = Bundle.main.path(forResource: lang, ofType: "lproj")
    let bundle = Bundle(path: path!)

    return NSLocalizedString(self, tableName: nil, bundle: bundle!, value: "", comment: "")
  }
}

в вашем контроллере просмотра

print(LanguageFile().home)

вы можете получить свою строку на основе языка вашего приложения.

Вы можете попробовать этот пример https://github.com/karthickkck315/Language

0 голосов
/ 27 мая 2018

Решено, мне не хватало @objc, поэтому селектор не может вызвать его

//MARK:- Bundle Extension
extension Bundle {

    @objc func specialLocalizedStringForKey(key: String, value: String?, table tableName: String?) -> String {
        let currentLanguage = Languages.currentAppleLanguage()
        var bundle = Bundle();
        if let _path = Bundle.main.path(forResource: currentLanguage, ofType: "lproj") {
            bundle = Bundle(path: _path)!
        } else {
            let _path = Bundle.main.path(forResource: "Base", ofType: "lproj")!
            bundle = Bundle(path: _path)!
        }
        return (bundle.specialLocalizedStringForKey(key: key, value: value, table: tableName))
    }
}
0 голосов
/ 25 мая 2018

Я добавляю это в файл main.swift (swift-3, но можно перенести в swift-4) ..

import Foundation

struct Static {
  static var token: dispatch_once_t = 0
  static var kBundleKey:Int = 0
  static var kLanguageKey:Int = 0
}

class SwizzleBundle : NSBundle {
  override func localizedStringForKey(key: String, value: String?, table tableName: String?) -> String {
    let bundle: NSBundle? = objc_getAssociatedObject(self, &Static.kBundleKey) as? NSBundle

    guard (bundle != nil) else {
      return super.localizedStringForKey(key, value: value, table: tableName)
    }

    return (bundle?.localizedStringForKey(key, value: value, table: tableName))!
  }

  override var preferredLocalizations: [String] {
      let bundle: NSBundle? = objc_getAssociatedObject(self, &Static.kBundleKey) as? NSBundle
      let language: String? = objc_getAssociatedObject(self, &Static.kLanguageKey) as? String

      guard (bundle != nil) else {
        return super.preferredLocalizations
      }

      return [language ?? : "en-CA"]
  }
}

extension NSBundle {
  static func setLanguage(language: String?) -> Void {
    dispatch_once(&Static.token) {
      object_setClass(NSBundle.mainBundle(), SwizzleBundle.self);
    }

    var path = NSBundle.mainBundle().pathForResource("Base", ofType: "lproj")!
    if let language = language {
      path = NSBundle.mainBundle().pathForResource(language, ofType: "lproj")!
    }

    objc_setAssociatedObject(NSBundle.mainBundle(), &Static.kBundleKey, NSBundle(path: path), .OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    objc_setAssociatedObject(NSBundle.mainBundle(), &Static.kLanguageKey, language, .OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  }
}

NSBundle.setLanguage("en-CA")
UIApplicationMain(Process.argc, Process.unsafeArgv, NSStringFromClass(Application), NSStringFromClass(AppDelegate))

Работает, изменяя язык ДО вызова UIApplicationMain.С этого момента вы можете менять язык в любое время, когда хотите, чтобы функция была быстро изменена.

Это сработало для меня на iOS 9. Я еще не тестировал его ни для чего выше.

...