When working on an application that needs to be translated into multiple languages, there is always the possibility of missing some of the strings that need to be translated. You can always switch into one of the other translations and look around for anything that didn’t get translated, but this has a couple of problems:

  • You may not yet have up-to-date translations for the current version of your application. In fact, the most common time to look for missing translations is when preparing to get the translations updated for a new release.

  • If you don’t understand the language you’re testing with, it’s much harder to navigate unless you’re really familiar with every nook and cranny of your application.

To solve these problems, I implemented a tool for the application I work on that helps with both of these problems. Our implementation is in Visualworks Smalltalk, but the idea could be used anywhere.

Every time our application changes, an automated build updates our reference translation files. I set up another automated build that notices these updates and generates a new translation called “Mirrored English”. It simply takes every English string in our message catalogs and “translates” it by reversing (mirroring) it.

We then run our UI, load the Mirrored English translation, and navigate throughout the UI. Anything we can read easily has not been included in the message catalog.

This tool solves both of the problems above. The translation is always current because it is auto-generated every time our message catalog changes. Also, because it’s just reversed English, it is still possible (though slower) to read the text in order to navigate correctly. Reversed text seems to force just enough cognitive load that my brain notices very quickly when a string hasn’t been reversed.

This is a simple idea, but there is a bit of a trick. A simple reversal of the string will usually break whatever marker tokens your programming language uses for string interpolation. In Visualworks, those tokens are < and >; Ruby uses #{ and }.

The core of our Mirrored English generator looks like this:

Mirrored English Generator
mirroredEnglishFrom: sourceFilename into: targetFilename
| catalog |
catalog := SimpleMessageCatalog fromXLIFF: sourceFilename.
catalog translationUnitsDo: [:each |
each translated: (self mirror: each untranslated))].
catalog writeXLIFFFile: targetFilename
mirror: aString
^aString reverse copyWithRegex: '>[^<]*<' matchesTranslatedUsing: #reverse

Note that this code uses SimpleMessageCatalog from ExtraCatalogs and Vassili Bykov’s Regex11 package.

The implementation in #mirror: finds the now-reversed string interpolation markers and “un-reverses” them. Thus, a string like “Perform <1s> on <2p>!” would be “translated” to “!<2p> no <1s> mrofreP”. In the actual UI, the interpolated parts of the string will not be reversed, so you have to watch for that when navigating and looking for untranslated strings.

I hope you find this trick useful in your application.