I did A LOT of translation work and in the end the best, easiest and fastest solution always was a list / map of key value pairs, where key was a unique translation identifier and the value was the translation in one language optionally having placeholders (e.g. for numbers) combined with a simple macro (best case) / function / method similar to sprintf.
Even plural forms should get their own unique identifier - automatic pluralization always failed for my use cases (russian has several different plural forms depending on the context).