I'm using a macro to simplify returning localised strings, like so:
#define GetLocalStr(key, ...) \
[NSString stringWithFormat:[[NSBundle mainBundle] localizedStringForKey:key value:@"" table:nil], ##__VA_ARGS__]
Basically, if you have an entry in a localisation Strings file like "name" = "My name is %@";
, calling
GetLocalStr( @"name", @"Foo" );
will return the NSString @"My name is Foo"
When I run it however, like:
NSString * str = GetLocalStr( @"name", @"Foo" );
I get the "format string is not a string literal" warning. Even following the advice of the other answers on SO about this warning and replacing it with:
NSString * str = [NSString stringWithFormat:@"%@", GetLocalStr( @"name", @"Foo" )];
I still get the warning, and besides, it kind of defeats the point of the macro making life easier.
How can I get rid of the warning short of wrapping all the GetLocalStr
calls in #pragma suppressors?
Edit 27/08
After running through CRD's answer and doing some more tests, it seems like I made a bad assumption on the error. To clarify:
Localisation Strings file:
"TestNoArgs" = "Hello world";
"TestArgs" = "Hello world %@";
Code:
NSString * str1 = GetLocalStr( @"TestNoArgs" ); // gives warning
NSString * str2 = GetLocalStr( @"TestArgs", @"Foo" ); // doesn't give warning
The majority of my translations take no arguments, and those were the ones giving the warning, but I didn't make the connection until I read through CRD's answer.
I changed my single macro to two, like so:
#define GetLocalStrNoArgs(key) \
[[NSBundle mainBundle] localizedStringForKey:key value:@"" table:nil]
#define GetLocalStrArgs(key, ...) \
[NSString stringWithFormat:[[NSBundle mainBundle] localizedStringForKey:key value:@"" table:nil], ##__VA_ARGS__]
And if I call each one separately, there's no warnings.
I'd like GetLocalStr
to expand to either GetLocalStrNoArgs
or GetLocalStrArgs
depending on if any arguments were passed or not, but so far I've been having no luck (macros are not my strong suit :D).
I'm using sizeof(#__VA_ARGS__)
to determine if there's any arguments passed - it stringifys the arguments, and if the size is 1, it's empty (i.e. `\0'). Perhaps it's not the most ideal method, but it seems to work.
If I rewrite my GetLocalStr
macro to:
#define GetLocalStr(key,...) (sizeof(#__VA_ARGS__) == 1) ? GetLocalStrNoArgs(key) : GetLocalStrArgs(key,##__VA_ARGS__)
I can use it, but I still get warnings everywhere it's used and there's no arguments passed, while something like
#define GetLocalStr( key,...) \
#if ( sizeof(#__VA_ARGS__) == 1 ) \
GetLocalStrNoArgs(key) \
#else \
GetLocalStrArgs(key,##__VA_ARGS__)
won't compile. How can I get my GetLocalStr
macro to expand properly?