Abedalkareem / LanguageManager-iOS

A Language manager to handle changing app language without restarting the app. It supports iOS and tvOS.
MIT License
396 stars 67 forks source link

No longer works since the swizzling removal. #46

Closed eldare closed 4 years ago

eldare commented 4 years ago

I've upgraded from v1.1.3 to v1.2.1, and it stopped working. LanguageManager.shared.setLanguage(language:) no longer has the same affect.

I went over the commits and noticed v1.1.4 had a change to the swizzling part: f98e6ee add new comments, remove the swizzling for the bundle I then tested with v1.1.4, and it doesn't work either.

Do I need to do something new to make it work again, since the swizzle removal?

I don't use StoryBoards and Nibs, everything is done programmatically. After calling setLanguage(language:) the rootViewController is reloaded as part of my app's architecture.

Thank you.

Abedalkareem commented 4 years ago

Hi, What exactly stopped working? are you using .localiz()?

if you can also explain what stopped working exactly. like the strings now are not getting localized? or something else?

eldare commented 4 years ago

Thank you for the quick response.

Yes, the strings stopped being localized. And I actually just realised how to resolve it, after reading this issue: https://github.com/Abedalkareem/LanguageManager-iOS/issues/27 Everything is working again.

I've added the code you provided:

public extension String {
  func localiz(comment: String = "") -> String {
    guard let bundle = Bundle.main.path(forResource: LanguageManager.shared.currentLanguage.rawValue, ofType: "lproj") else {
      return NSLocalizedString(self, comment: comment)
    }

    let langBundle = Bundle(path: bundle)
    return NSLocalizedString(self, tableName: nil, bundle: langBundle!, comment: comment)
  }
}

And then changed the Swiftgen template we're using to call the localiz() method: (unrelated to your lib, I just think it might help someone in the future)

extension Text {
  private static func tr(_ table: String, _ key: String, _ args: CVarArg...) -> String {
    // let format = NSLocalizedString(key, tableName: table, bundle: Bundle(for: BundleToken.self), comment: "")
    let format = key.localiz()
    return String(format: format, locale: Locale.current, arguments: args)
  }
}

@Abedalkareem If I may suggest, it should be explicitly explained in the README.md, that localiz() needs to be called from v1.1.4+, due to the swizzle removal. While I'm against swizzling in general, I think cases like these are a good example of when it's ok to swizzle. Too bad you had to remove it.

Also, can you please explain how LanguageManager can function properly without swizzling when it comes to Storyboards and Nibs?

Thanks again.

Abedalkareem commented 4 years ago

Hi Eldare, Sorry for the inconvenience, so actually still I kept swizzling to localize the storyboard and XIB part. as there are no other solutions to do localization for them. so what I'm doing I'm replacing the implementation of awakeFromNib with this:

 @objc func swizzledAwakeFromNib() {
    swizzledAwakeFromNib()

    switch self {
    case let txtf as UITextField:
      txtf.text = txtf.text?.localiz()
      txtf.placeholder = txtf.placeholder?.localiz()
    case let lbl as UILabel:
      lbl.text = lbl.text?.localiz()
    case let tabbar as UITabBar:
      tabbar.items?.forEach({ $0.title = $0.title?.localiz() })
    case let btn as UIButton:
      btn.setTitle(btn.title(for: .normal)?.localiz(), for: .normal)
    case let sgmnt as UISegmentedControl:
      (0 ..< sgmnt.numberOfSegments).forEach { sgmnt.setTitle(sgmnt.titleForSegment(at: $0)?.localiz(), forSegmentAt: $0) }
    case let txtv as UITextView:
      txtv.text = txtv.text?.localiz()
    default:
      break
    }
  }

to localize the text.

Thank you again and sorry for the delay I just so your comment.

ryanrizzo commented 3 years ago

Hi @Abedalkareem,

I think there may be a better solution than swizzling. You could just override awakeFromNib() like this:

extension UIView {
    open override func awakeFromNib() {
        super.awakeFromNib()
        switch self {
        case let textField as UITextField:
            textField.text = textField.text?.localize()
            textField.placeholder = textField.placeholder?.localize()
        case let label as UILabel:
            label.text = label.text?.localize()
        case let tabBar as UITabBar:
            tabBar.items?.forEach({ $0.title = $0.title?.localize() })
        case let button as UIButton:
            button.setTitle(button.title(for: .normal)?.localize(), for: .normal)
        case let segment as UISegmentedControl:
            (0 ..< segment.numberOfSegments).forEach { segment.setTitle(segment.titleForSegment(at: $0)?.localize(), forSegmentAt: $0) }
        case let textView as UITextView:
            textView.text = textView.text?.localize()
        default:
            break
        }
    }
}