Language Manager

QLangManager is a small class that provides developers of translated applications a comfortable way to provide a fully functional language menu. New translation files are detected automatically upon application startup and the switching of the current language is done on-the-fly and doesn’t require an application restart. Due to the way QLangManager works, the language names in the menu can be displayed in the respective languages themselves, without the need for any hard-coded translated strings (possibly containing obscure UTF-8 characters and breaking flexibility).

Screenshots

Here are some screenshots of the demo application, which you can obtain in the download section. As you can see, this demo application has translation files for German, English, Greek, French and Icelandic. (I don’t guarantee for eloquence of the greek and icelandic translation, though.)

Internationalizing with Qt in a nutshell

If you’re already familiar with internationalization (translation) of Qt applications, feel free to skip this section. If you want to learn about the topic more in-depth, you should look at the respective Qt tutorial and/or the Qt Linguist manual.

Internationalizing your application with Qt is easy, especially if you’re at the beginning of development. All you basically have to do, is wrap all hard-coded strings inside a tr function. e.g.

QMessageBox::information(this, tr("My Application"), tr("Hello there!"));

If you’re working with QtCreator or a similarly powerful IDE, all static strings in the user interface of your application (like button and label captions) will automatically be marked for translation. If you’re not using an IDE that handles user interface strings/setup for you, you must use the tr function manually when setting the user interface strings.

Once that’s done, we need to modify the project file so the tools we use in the following steps know, for which languages we want translation files to be created. In the .pro file, we add something like:

TRANSLATIONS += tr_en.ts \
    tr_de.ts \
    tr_fr.ts \
    tr_el.ts \
    tr_is.ts

These are the raw translation files that will be generated later, one for each language. Here, we want translations for English, German, French, Greek and Icelandic. The two-character language code follow the ISO 639 standard. The easiest way to get that string, is creating a QLocale object with the wanted language and outputting the QLocale::name() string (See Qt documentation). The prefix of those files (here “tr”) can be anything, e.g. your application name.

Now we actually create the .ts files we specified in the project file by calling
lupdate MyProjectFile.pro
in the terminal/console. In the project directory there now should be those .ts files with all the extracted strings. If during the development of your application, new strings are created that need translation, just run the above command again and the .ts files will be updated.

These .ts files can now be opened with Qt Linguist and you can start translating the strings in the respective language.
When that’s done, we need to release the translation, i.e. create the compressed translation files (same names as the .ts files but with .qm ending) from the ts files. In Linguist you do this via fileRelease for every translation file. Alternatively you can call
lrelease MyProjectFile.pro
on the terminal/console to release all .ts files associated with the project at once.

Now you have a bunch of .qm files which provide your application with the appropriately translated strings during runtime.

Setting up QLangManager

QLangManager consists of just a header and a source file which you can get in the download section below. Use them like any other .h/.cpp-pair for a class in your project.
In QtCreator, this means adding both files to your project.
Then, just #include the qlangmanager.h file wherever you need it, typically in the main window header file.

Using QLangManager

We assume, the translation files are named properly, e.g. tr_en.qm, tr_fr.qm etc. (ISO 639 standard) and are placed in the subdirectory translation whithin your project directory.
After the implementation described below is done, run lupdate on your project again and you will see that a new translatable string got available, that says “English” and as a comment by the developer says “This must be the native name of the language of this translation”. This is the string that will be shown for the respective language menu entry you’re just translating. So when working on the german translation, don’t translate that string to “Englisch” (german for “english”), but translate it to “Deutsch” (german for “german”).

Add a QLangManager instance to your main window class, e.g. like so:

class MainWindow : public QMainWindow
{
  Q_OBJECT

public:
  explicit MainWindow(QWidget *parent = 0);
  ~MainWindow();

private:
  Ui::MainWindow *ui;
  QLangManager languageManager; // here it is
};

In the constructor of your main window, you first tell QLangManager where to search for translation files of your application, and where to search for the translation files that are specific to Qt. Those are named “qt_[language code].qm” and contain translations of Qt-internal strings like default “Ok” button texts etc. Find them by running a search for that typical “qt_*.qm” pattern in your Qt installation directory and ship them with your application translation files for an optimally internationalized application.

// set directory with application transflation files and their prefix (and suffix, if necessary):
languageManager.setTranslationFiles(qApp->applicationDirPath()+"/translation", "tr_");
// set directory with Qt translation files (e.g. for month names, default dialog messages etc.):
languageManager.setQtTranslationFiles(qApp->applicationDirPath()+"/translation", "qt_");

Then you may also provide icons for the language menu. Typically they will be inside a resource file, so we specify a resource path (hence starting with a colon). They also must be named following the pattern “[prefix][language code][suffix]”, e.g. a british flag could be named en.png when prefix is empty, the language is english and suffix is “.png”.

// use flag icons from resource with suffix ".png":
languageManager.setFlagIconFiles(":/flags", "", ".png");

The flag icons used in the example are made by Mark James and are public domain. You may download them (and many many more great free icons) from his website famfamfam.com.
If you’re using Ubuntu with gnome, the icons may not show up. This is because gnome has menu icons disabled by default. How to enable this is explained on the internet.

Finally, we let QLangManager create the actual menu. For that, prepare a menu item in the main menu which will be the parent of all the menu items representing each available language. In this example, we’ll call that parent menu item ui->menuLanguage of type QMenu*.

languageManager.createLanguageMenu(*ui->menuLanguage);

This populates the parent menu with all languages that can be found in the previously set directory and with the specified file name pattern. The menu items are fully functional, however, to see an immediate effect upon triggering a language change, make sure to also follow the instructions in the next section Making On-The-Fly language changing possible.

You can set the current language programmatically after initializing QLangManager (e.g. for loading the configured language setting from a settings file) with the QLangManager::setLanguage() function. This function takes a QString which must either be the two-character language code (“en”, “de”, “fr”,…) or a five character language-and-country code (“de_DE”, “en_US”, “en_GB”,…) as outputted by QLocale::name(). In the latter case, the country code is ignored, only the first two characters are used.
If, for example, you want to set the system language as current language, call

languageManager.setLanguage(QLocale::system().name());

So when quitting the application, if you want, you can save the string QLangManager::language() to some settings file and restore the configured language upon starting the application by loading that string from the file and passing it to QLangManager::setLanguage().

That’s it!

Making On-The-Fly language changing possible

To change the translation of the application during runtime, e.g. before setting UI strings, you must catch the event of a language change. To do that, just insert a private function changeEvent(QEvent *e) in your main window. Your class header now looks something like this:

class MainWindow : public QMainWindow
{
  Q_OBJECT

public:
  explicit MainWindow(QWidget *parent = 0);
  ~MainWindow();

private:
  Ui::MainWindow *ui;
  void changeEvent(QEvent *e); // here's the added event handler
  QLangManager languageManager;
};

and give an implementation that retranslates all user interface strings. QtCreator/QtDesigner users can just use this boiler plate code for that:

void MainWindow::changeEvent(QEvent *e)
{
  QMainWindow::changeEvent(e);
  switch (e->type()) {
  case QEvent::LanguageChange:
    ui->retranslateUi(this);
    break;
  default:
    break;
  }
}

So as soon as we change the language, this event gets fired and the whole application is retranslated with the new translation file during runtime. This event handling thing isn’t specific to QLangManager but is also needed if using different language handling code.

Note that some QtCreator versions automatically add this event handler to your main window.

Download

QLangManager sources files: QLangManager.tar.gz
QLangManager example project: QLangManager-example.tar.gz
Release date: 11.11.2011