SwiftGen: Strings: valid format `% d` is ignored by SwiftGen, but still formatted.
100% daily becomes 1000aily because the Swift template function tr always returns String(format: format, locale: Locale.current, arguments: args) even if args is empty.
% (followed by space) is afaik the invisible plus sign so somehow String(format: interprets it like a valid format argument (not sure if it should).
But the problem is that the tr function should just return the result from NSLocalizedString if no args. So just adding guard !args.isEmpty else { return format } before the last line would fix it.
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Comments: 28 (9 by maintainers)
The problem is that, per fprintf-style standard,
%is interpreted as a placeholder. Like for%dor%@etc. If you want a literal%, you need to escape it by doubling it, using%%in yourLocalizable.strings(see the man page for the fprintf-family of functions). You can see it as being similar to when you have\nor\rin a string and if you want a literal\you need to double it using\\. This is very similar here.This is not really related to SwiftGen itself, but to how
String(format: )works.@djbe @AliSoftware Yes! thank you so much for your understanding! great product by the way!
@franmowinckel I’d like to again apologise for quickly closing and dismissing the issue, we’ve had some previous issues where the user didn’t understand the
%%syntax, and we just assumed this was a duplicate.I’m really glad you stuck with us though, and helped us understand the underlying issue. Hopefully when you report any future issues or requests, this will go better. 😅
Wooow I actually really thought that we were already skipping the
String(format:)forletconstants… but indeed I just looked back at the generated code and we call the sametrfunction, you’re right. We should indeed have a differenttrfunction with no additional CVaArg and that skips the call toString(format:)then, indeed… My apologies, I was so convinced we already had a separate function, and was so confused by the fact that your original issue looked a lot like what other people have reported when they just didn’t know that they should use%%😓So in the end:
% disn’t recognised as a valid placeholder, while per the sprintf spec it should be seen as one. That means that100% dailyshould lead to astatic func foo(_ p1: Int) -> Stringand not alet foo: Stringlike it does currently.String(format: )when using aleti.e when there’s no placeholders detected and extra parameters to pass"100% daily"example would still need to be escaped to"100%% daily"— because SwiftGen couldn’t know that you meant a literal%otherwise, given that% dshould be considered as a valid placeholder — once we fixed (1).I apologise, I only got around to reading the format docs now (on phone all day), and you’re completely right,
% dis a valid conversion specification, and SwiftGen incorrectly ignores it.We’ve been focusing the whole time on the wrong issue (thinking we should somehow circumvent this), whereas the actual issue is that SwiftGen should properly parse this and generate a
static funcwith an integer parameter.