I have a String extension that helps me internationalise.
public extension String {
    var localized: String {
        return NSLocalizedString(self, tableName: nil, bundle: Bundle.main, value: "", comment: "")
    }
    func localized(args:CVarArg...) -> String{
        return NSString.localizedStringWithFormat(self.localized as NSString, args) as String
    }
}
This way I can easily use "hello_world".localized anywhere in the app and it works nicely.
Now I want to have the same functionality, but also want to be able to pass arguments. However passing the 'CVarArg...' doesn't seem to work as I'd expect it to.
"grant_gps_access".localized("MyApp")
Expected result: "Please grant MyApp GPS access"
Actual result: "Please grant (\n MyApp\n) GPS access"
What am I missing here?
You cannot pass a variable argument list to another function, you 
have to pass a CVaListPointer instead (the Swift equivalent
of va_list in C):
public extension String {
    var localized: String {
        return NSLocalizedString(self, tableName: nil, bundle: Bundle.main, value: "", comment: "")
    }
    func localized(args: CVarArg...) -> String {
        return withVaList(args) {
            NSString(format: self.localized, locale: Locale.current, arguments: $0) as String
        }
    }
}
Since NSString.localizedStringWithFormat has no variant taking a
VAListPointer, the equivalent NSString(format:, locale:, arguments:) 
with the current locale is used.
Even simpler (attribution goes to @OOPer): Use
String.init(format:locale:arguments:) which takes a 
[CVarArg] argument:
    func localized(args: CVarArg...) -> String {
        return String(format: self.localized, locale: Locale.current, arguments: args)
    }
Now
"grant_gps_access".localized(args: "MyApp")
should work as expected, assuming that the strings file contains the entry
"grant_gps_access" =  "Please grant %@ GPS access";
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With