Another thing is that the mini-language grows complex enough that the resulting text can be quite hard to read and understand:
{people, plural, offset:1 =0{No one went.} =1{{user1} went.} =2{{user1} and {user2} went}.} other{{user1} and # others went}}.
is just a single (or two) placeholder and it takes a while to even parse how it's supposed to work. (case (length folks) (0 "No one went.")
(1 ((elt 0 folks) " user went."))
(2 ((elt 0 folks) " and " (elt 1 folks) " went."))
(otherwise ((elt 0 folks) " and " (length folks) " others went.")))
You can wrap that in a lambda that concatenates resulting strings and voilà, you have "smart" string tables. And it's not a problem to make it even more DSL-y and translator friendly.Also, I advocate closer work between translators and developers. Let the translators give the text and explain corner cases to someone who can code up the logic.
BTW. Lisp is only hard for people who acquired this stupid meme that "Lisp is weird/for crazy people". You'd be hard-pressed to find something which is simpler in terms of syntax and readability.
The way L10ns try to mitigate the complexity of the markup language is to provide buttons for pasting the correct markup for translators. Also a developer translates on his own language first. And this example will always be visible to the translator of an another language for easy reference. So the programmer offloads the logic thinking from the translator.
IMO ICU's messageformat markup is also slowly becoming the standard for localizing strings. It is already used widely by big organizations such as Apple, Google and Yahoo.
L10ns pre-compiles all message string. So it offloads the parsing performance.