4

I have a Localizable.strings file for my project's i18n, and a lib uses KYLocalizable.strings.

I have considered to make Localizable.strings "subclass" from KYLocalizable.strings, but it cannot as far as I know. So instead, I want to define a function macro like what SDK does:

#define NSLocalizedString(key, comment) \
    [[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:nil]
#define NSLocalizedStringFromTable(key, tbl, comment) \
    [[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:(tbl)]

Pseudo code:

#define CustomLocalizedString(key, comment) \
    // if key exists in Localizable.strings
    //   use it
    [[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:nil]
    // else
    //   search it in KYLocalizable.strings
    [[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:@"KYLocalizable"]

so I can just use CustomLocalizedString(<key>, <comment>) in my project.
But how to check whether the key exists in Localizable.strings or not?

Thanks in advance!!

Kjuly
  • 34,476
  • 22
  • 104
  • 118

5 Answers5

6

In this call:

[[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:nil]

The value parameter (currently an empty string) will be used if a string can't be located in your strings file using the specified key. So... all you should need to do is place your second lookup to KYLocalizable.strings as the value to that parameter. The code would look similar to this (I didn't actually run this, but it should be close):

[[NSBundle mainBundle] localizedStringForKey:(key) 
    value:[[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:@"KYLocalizable"]
    table:nil]

At that point, the string in Localizable.strings will be used if found. Otherwise, the value in KYLocalizable.strings will be used. If it isn't found either, then a blank string will be returned (since that is what is specified in the nested value parameter).

However, one inefficiency of this approach is that your application will actually attempt the lookup in KYLocalizable.strings first on every attempt (so that this result can subsequently be passed in as the value parameter when doing the outer lookup to Localizable.strings). If you actually want to check Localized.strings first, and then only do a second lookup if the string isn't found, I think you'd need to create a method with that logic in it (for example, add a method in a category on NSBundle).

jolson474
  • 61
  • 1
  • The lack of efficiency bums me out, but as the place I'm using this code isn't fired often (it's only for errors), it'll do. Thanks! – LoriHC May 09 '13 at 13:43
4

If the key doesn't exist, the string you will receive will be the key itself. So as long as you suppose you will never use the key as a localized string, you can test if NSLocalizableString returned you the key or not.

Xval
  • 938
  • 5
  • 17
0

Thanks @Xval, I've just figured it myself and here's a simple function (please offer some suggestions if you have a better idea):

#define KYLocalizedString(key, comment) \
  [[[NSBundle mainBundle] localizedStringForKey:(key) value:nil table:nil] isEqualToString:(key)] ? \
  [[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:@"KYLocalizable"] : \
  [[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:nil]

localizedStringForKey: will return a NSString that as @Xval said. :)

Kjuly
  • 34,476
  • 22
  • 104
  • 118
0

For Swift:

var key = "your_key"
NSBundle.mainBundle().localizedStringForKey(key,
                                             value: NSBundle.mainBundle().localizedStringForKey(key, value:"", table: nil),
                                             table: "Your_Custom_Localizable_File")

Just to clarify things, according to Apple's documentation:

If key is not found and value is nil or an empty string, returns key.

So using this technique you can nest calls to as many localization files as you want.

Foti Dim
  • 1,303
  • 13
  • 19
0

I wrote this handy extension for localized strings, so you can just use the localized() function to get the localized string(you can also pass arguments) and the isLocalized computed property to check whether the string is localized or not:

extension String {

    var isLocalized: Bool {
        return localized() != self
    }

    func localized(parameter: CVarArg? = nil) -> String {
        if let parameter = parameter {
            return String(format: NSLocalizedString(self, comment: ""), parameter)
        }
        else {
            return NSLocalizedString(self, comment: "")
        }
    }

    func localized(parameter0: CVarArg, parameter1: CVarArg) -> String {
        return String(format: NSLocalizedString(self, comment: ""), parameter0, parameter1)
    }

}
Bruno Paulino
  • 5,611
  • 1
  • 41
  • 40