5

To provide a fallback language for NSLocalizedString, I'm using this #undef and #define in Objective-C:

#undef NSLocalizedString
#define NSLocalizedString(key, comment) @"NSLocalizedString has been replaced";

This works perfectly well if called from Objective-C, but if called from Swift, the new definition of NSLocalizedString is ignored. (bridging header is configured correctly and works)

Is this possible in Swift, and if so, how?


Note: the real example is here on Github, also see SO answer here

Community
  • 1
  • 1
Dan Rosenstark
  • 68,471
  • 58
  • 283
  • 421

2 Answers2

3

You can do this for NSObject subclasses like this

extension NSObject {
    func NSLocalizedString(key: String, comment: String) -> String {
        return "yes we have localized an NSObject"
    }
}

What about AnyObject? In this case, you would have to be aware of and conform to the FallbackLanguage protocol in your AnyObject subclass

protocol FallbackLanguage: class {}

// add default implementations
extension FallbackLanguage {
    func NSLocalizedString(key: String, comment: String) -> String {
        return "yes we have localized AnyObject via FallbackLanguage protocol"
    }
}

Notes

  • These two solutions can both be in your project without any issues.
  • If you're calling NSLocalizedString outside of a class instance, you're out of luck.
Dan Rosenstark
  • 68,471
  • 58
  • 283
  • 421
  • 1
    Big thanks to this answer for how to extend AnyObject: http://stackoverflow.com/a/31988258/8047 – Dan Rosenstark Nov 13 '15 at 16:26
  • Or you could just extend UIViewController, UIView and possibly some other classes where NSLocalizedString is called in virtually all cases. – Lukas Kalinski May 27 '16 at 16:23
  • so narrow this to several unrelated superclasses which happen to all share nsobject as their super? – Dan Rosenstark May 27 '16 at 16:26
  • Oh, sorry, you're right. I focused on the AnyObject extension discussion and forgot about that virtually everything that inherits from the API also inherits from NSObject. – Lukas Kalinski May 27 '16 at 16:30
  • This used to work, but suddenly I get: "Use of instance member 'NSLocalizedString' on type 'NSObject'; did you mean to use a value of type 'NSObject' instead?" and "Extra argument 'comment' in call" – Colin Swelin Jul 07 '16 at 19:42
  • @ColinSwelin just tried this in a playground with no issues. Please post a playground (as a gist on Github or whatever) and perhaps we can help? – Dan Rosenstark Jul 07 '16 at 21:22
  • @ColinSwelin I'm seeing what Colin is too. "Extra Argument in call". – jasonjwwilliams Oct 20 '16 at 00:51
  • @jasonjwwilliams what version of Swift are you using? On Swift 2.x this works well... not sure about Swift 3 – Dan Rosenstark Oct 21 '16 at 20:10
  • still good in Swift 3, https://gist.github.com/drosenstark/a1dd2fd53a3041c92922e53c8a931012 – Dan Rosenstark Mar 28 '17 at 18:41
1

You will have to do a global function... the other options will cause all sort of problems, such as retrain cycles, or classes classes witch do not inherit from NSObject(that is only subset of the problems) - this will not work at all. yes global function usually are big no! but that is the only way to "override" global function. , Here is a code I use in production, we had few thousands of string, at some point we had to make our app dynamically localized - and this is what we did.

// Global functions for lagacy code
func NSLocalizedString(_ key: String, comment: String) -> String {
    return key.localized()
}

func NSLocalizedStringInTable(key: String, tableName: String ) -> String {
    return key.localized(using: tableName)
}
Alex
  • 159
  • 1
  • 9