Internationalization

VisIt is being adopted all over the world as a tool of choice for visualization and data analysis. Since the VisIt user community is becoming increasingly broad, it makes sense to start to translate the user interface into other languages.

VisIt uses the Qt library for its user interface and Qt provides built-in support for creating multi-language applications. Although VisIt uses Qt for its GUI and viewer applications, which are the main applications that you see on the screen, practices conducive to creating an internationalized application were not always followed over the course of VisIt's development. Many of these deficits have since been corrected though some do remain -- primarily in areas of the code where there can be no dependence on Qt's internationalization mechanism. This wiki page will list the procedure for turning VisIt into an international application as well as some of the difficult issues that will still need to be addressed.

As an aside, we've often talked about having the ability to let someone pick a particular "vocabulary" since different disciplines often have different names for the same thing. For example, depending on your background, you might call a "cell" a "zone", "element". It is conceivable that we could use the internationalization capability to create slightly specialized locale translations that rename certain words so we don't have a proliferation of different names for the same thing in VisIt's user interface.

Creating a new translation

The first step in creating a new translation for VisIt is to run Qt's lupdate command on the source that will need to be translated. The lupdate command scans the source for tr()'s and builds a large .ts file, which is input for Qt linguist, that contains the text to be translated along with the translations and the status of each translation. Note that you may run lupdate on an existing .ts file in order to pick up new items in the code that need to be translated. Your existing translations in the .ts file will not be lost.

lupdate gui/*.C viewer/main/*.C viewer/main/ui/*.C winutil/Qvis*.C \
    plots/*/Qvis*.C plots/*/*GUIPluginInfo.C plots/Spreadsheet/SpreadsheetViewer.C \
    operators/*/Qvis*.C  operators/*/*GUIPluginInfo.C \
    tools/dev/xmledit/*.C \
    -ts resources/translations/lang.ts

The above command when run from the top /src directory in VisIt will create a .ts file for all of the GUI code that needs to be translated into another language. The file will be saved into the resources/translations directory where all translation files must be placed so VisIt can locate them. Once you have your .ts file, open it in Qt linguist and begin translating. Qt linguist makes it easy to iterate over the items that need to be translated, and takes care of complexities such as remapping keyboard shortcuts for translated menu items, etc. Every translation can even be assigned a degree of confidence such as guess or correct. That way, multiple people can contribute to the translation process. The Trolltech site has a good tutorial for users of Qt linguist.

.ts Files for VisIt

Here are .ts files for VisIt 2.5.0. To save the files, right click on them and choose Save target as or your browser's equivalent function.

If you have built VisIt then you can use Qt4's Qt Linguist application to edit the translation file. You might also want to check a translation for your language of interest has been started by looking at the translation directory in anonymous svn. If a translation has been started for your language, please get the .ts file from the svn link so you don't start over entirely.

You can send your updated translation file to visit-developers@ornl.gov or you can always join the VisIt team or post your translation file using the Media markup into this wiki page.

Creating the .qm file

Once you have completed working on a translation .ts file, run the lrelease command from Qt to create a qm file, which is a file format for the final translation that provides fast lookups.

lrelease lang.ts -qm lang.qm

Both the ts and qm files should be stored in the src/resources/translations directory. The naming scheme for the files should include the name of the locale that the translation represents. For example, the default locale for US VisIt developers is "en_US" so if we needed a US-English translation for VisIt then we could create translation files called visit_en_US.ts and visit_en_US.qm.

The programming mechanics of internationalization

In the source code, to annotate a string as content that can be internationalized, you must use Qt's tr() function. Any object inheriting from QObject automatically gets its own version of the tr() function that lets Qt figure out the context in which your translated word exists.

Using the tr() function

QLabel *label = new QLabel(tr("File"), this, "label");

Note the use of the tr() function on the string that the user will ultimately see in the QLabel. The tr() function lets you identify text that you want to translate. Suppose there is a French translation installed on the application, the call to tr("File") causes the translation to be searched for the key "File", which returns "Fichier". If the translation is not complete and there is no translated entry for "File" then the "File" string is returned from tr().

Translating in code that does not inherit QObject

Sometimes you are translating code that does not exist in a class that inherits from QObject. It's still possible to use tr().

void
function(void)
{
   Warning(QObject::tr("The text to translate", "function"));
}

Dynamically created strings

Sometimes creating a translation is not as easy. Consider the case where you have a dynamically created error message. Most of the string can be translated but there are portions that are filled in at runtime. Furthermore, the order of the text replacement in the translation may differ in the target language, which is why we do not translate just a few words at a time. Translating the entire sentence with designated wildcards lets the translator create the most appropriate translation. To deal with these complexities, follow this pattern when programming.

Use the QString::arg function to pass values in for the %1, %2, ... wildcards.

QString dirName, hostName; // Assume these are filled in by now.

// The basic message to be translated. The %1 and %2 are wildcards that will also 
// appear in the translated string and they will be used as the targets for text
// replacement.
QString msg(tr("The metadata server could not read directory %1 on host %2.").
    arg(dirName).arg(hostName));

// Tell the user about the error.
Error(msg);

Difficulties

Some parts of the internationalization process are not as straightforward as creating a Qt translation file for the GUI elements. As was mentioned before, there are areas of VisIt that do not use Qt. What should be done for them?

  • VisIt Qt installations don't have Qt linguist, lupdate, lrelease installed. I had to build them for Mac.
  • Errors/warnings from down in AVT, caused by exceptions, etc. These sorts of messages may need to be separated out into a new .so that can create a specific error/warning with a known ID. We talked about this for turning off specific errors/warnings anyway.
  • Query names and query text output
  • CLI generated errors/warnings
  • "Default" color table string can be translated easily in the GUI but its translation would need to be understood down in AVT.
  • "default" variable name -- same as above