One thing that changed this for us: store a hash of the source string in the translation file itself, as an extra column beside each translated cell, instead of diffing two exports.
The difference is where staleness lives. A two file diff only tells you which rows moved between export A and export B, so you have to keep the previous export around, and a reordered or regenerated export muddies it. A stored source hash makes staleness a property of one row in one file: if the hash of the current source doesn’t match the recorded one, that translation was reviewed against different text. Added and removed keys fall out of the same pass.
Keep the short source string rather than only its hash and the report can also show what the line used to say, which is usually a two second decision for the reviewer.
That’s roughly what gettext fuzzy flags are, with the bookkeeping already done for you.