I've been working on a Rails project recently that needs to be in multiple languages. Rails supports multiple languages by having you replace every piece of text in every view with a t(...) method that looks up keys in a language-specific config file (e.g. config/locales/en.yml or config/locales/fr.yml).
This system works nicely but on any reasonably complex project, especially if there are multiple developers and designers working on it, it's easy to accidentally have tags on pages that aren't set up in the language files.
I have to admit that I don't have 100% test coverage on all of my projects (I don't floss every day either), but I like to at least "smoke test" as many of the views as possible. In my functional tests, I have some "assert_select" calls for every view, to make sure that the pages are rendering their content properly.
Today I got some notes from the designer about views missing translated text, so I decided to add an assertion to every view test to automatically ensure they don't have missing translation tags.
The trick with this is that if a translation is missing, Rails will automatically wrap the message in a span with class "translation_missing". All I have to do is check that this selector doesn't show up on the page. Rails' "css_select" method returns an array of matches, so I just ensure that the result has a size of 0.
After putting this into several functional tests, I quickly realized that this could be wrapped up into a custom assertion.
I added this to my test_helper.rb file:
So now I just add assert_no_missing_translations to every view test - and now I won't miss translations any more.
Not bad for 10 lines of code!
The first version just returned a simple error message and the request url. This was already a big win compared to missing text in public-facing pages - especially since it only took five minutes to write. But I went back to this code a few hours later and got it to return the names of the specific missing tags. This took an extra ten minutes, mostly in figuring out the regular expression and the error return format - but it's already saved way more time than that, not to mention the embarrassment!