If awk hasn't had a chance of seeing the literal string in the body of the
program, your only option is to pass literals. Examples:
# works, because awk sees the "%s\n%s\n" string while parsing the
# program text and interpolates it
awk 'BEGIN{ esc="%s\n%s\n"; printf esc, "foo", "bar" }'
# does not work, because awk never sees the \n in full
awk 'BEGIN{ esc="%s\\"; esc=esc"n%s\\"; esc=esc"n"; printf esc, "foo","bar" }'
when reading the first argument to printf from the outside, you're in the
same situation as the second example.
In other words, it seems like it's not printf that understands \n and
other escape sequences, but the awk interpreter itself (if it has a chance
to see them).