There are a number of little tricks about the i18n process that have accumulated on various mailing lists and other places. A couple of the less obvious traps are listed here.
In addition to this list, you should also carefully read the document [menthos] by Christian Rose, one of the GNOME Translation Project's coordinators. That document contains a number of sample situations and advice about writing easily translatable text (not just the obvious stuff, such as avoiding idioms, but also more subtle issues such as not translating text markup). In fact, I am making Christian's effort required reading for people reading this tutorial — that way I can avoid duplicating any of his excellent work.
Do not ever mark an empty string for translation. This has the effect of retrieving the header section from the respective language file, rather than returning an empty string.
While it is relatively simple to avoid writing code such as _(""), you may need to be careful if the string is dynamically created. If there is any possibility that it might be empty, check first and do not call _() if there is no content to translate.
If you are trying to test an internationalised application, you will need to remember to run make install to see the results of any translations. Because the i18n support in the library is initialised with the explicit path to where the message files are stored (the second parameter to bindtextdomain()), that is where the program will look. There is no fallback in place to look in the current directory if something is not found in the specificed locale directory.
When creating the About box for your application, one of the fields you can pass in is the translator's name. In order to display the translator for the current locale, most GNOME applications have code similar to the following:
gchar *translator_credits = _("translator_credits"); ... about_box = gnome_about_new(... strcmp (translator_credits, "translator_credits") != 0 ? \ translator_credits : NULL, ...
Translators then translate the translator_credits string to their own name. If nobody translated the current locale (and so the _() call returned the original string), then no translator credits are passed into the about box's constructor and that tab is not available.
It is recommended that you use the string translator_credits for this purpose, since translators are becoming used to seeing that string and knowing how to translate it in the correct context.