Internationalization


This short article explains how to use built-in internationalization features and add support of different languages into your applications.



Translation matrix

The main concept of internationalization of applications is to store key-value pairs where key is the text to be translated and the value is the translated text(it is a simplified description of cause). The Nitisa framework has special class to store such pairs. This storgate is called translation matrix and is described by ITranslate interface and implemented in CTranslate class. You can access instance of the ITranslate interface via Application->getTranslate() method. It has t overloaded method used for translation. Of cause you have to add translated values first. If you don't do it, the t method will return the key value you passed to it. To add translation there are 2 methods: Add and Set. The difference between them is the first one just adds data without checking if it already exists and the second one doesn't add data if it aleardy exists but replace it. When you initialy load translation texts into your application, use Add method. It will work much faster, especially if you load a lot of texts. When adding translation texts you have to specify target language, category, key(usually it is a text which require translation), and translated value. You can place all translation into the same category(for example, "app") or split them into several categories. It can be usefull for large applications and when the same key should be translated into different values in different places. For example, the word "Login" may be places on button and means "sign in", or may be placed on Label near an input and means "user login/name used to authorize". In English you can use word "Login" in both cases, but in some other languages, like Russian, it is mistake. So you can use the same key on both controls(key will be "Login") but different categories(for example, "auth" and "edit_user").

Usage

Where to put code for loading translation? Usually the answer is simple: right after creation of the application class instance.

void main()
{
    CApplication app;       // Create application                            // <- Here is the place where to setup translation matrix
    app.CreateForm(&Form1); // Create form    // ...
}

You can do it in many ways. If you need only a few words/sentences to be translated, you can write it directly. If you have a lot of texts or you store all translations in file/database, you can move translation matrix filling into a separate function. You even can create your own class derived from CApplication and write translation matrix filling in it's constructor. The choise is yours. Here is an example how it can be.

void main()
{
    CApplication app;       // Create application 
    app.getTranslate()->Add(L"ru", L"app", L"Hello user", L"Привет пользователь");
    app.getTranslate()->Add(L"ru", L"app", L"Logout", L"Выход");
    app.getTranslate()->setLanguage(L"ru");
    app.CreateForm(&Form1); // Create form    // ...
}

You may already pay attention on the app.getTranslate()->setLanguage(L"ru"); line. This sets current language.

Sometimes it is not possible to set all translations right after application creation. Don't worry, you can fill translation matrix at any point in your application. The only problem is that some controls or forms load texts at the creation time and when you fill translation matrix they already may have been created with untranslated texts. If after filling translation matrix you call ITranslate->setLanguage() method, it will also send notifications to all objects in you application and they will reload correct translated texts. But there may be situations when you cannot call this method either because correct language is already set or for another reason. In this case you have to send such a notification manually. Do it by IApplicationService::SendTranslateChangeNotification() method like shown below.

Application->QueryService()->SendTranslateChangeNotification();

Which categories and keys are used in controls/forms and other framework objects you can find on the corresponding object page in Reference. For example, look at Color form documentation. It uses category FormColor and has several keys, like Select Color and Cancel, which can be translated. So, to translate caption to russian language all you need is to add following line after application creation.

app.getTranslate()->Add(L"ru", L"FormColor", L"Select Color", L"Выберите цвет");

If you don't want to translate but want to change texts of objects of the framework, you may do it like this:

app.getTranslate()->Add(L"en", L"FormColor", L"Select Color", L"Choose Color");
app.getTranslate()->setLanguage(L"en");

This will change title of the Color form from Select Color to Choose Color.

In the keys for translation you may also specify parameters to be replaces later by specified values. In this case you have to use t method which accepts params value. The following examples shows how to use it.

s1 = Application->getTranslate()->t(L"app", L"Hello {user}", { { L"{user}", L"John" } });
s2 = Application->getTranslate()->t(L"app", L"Shown {count} products of {total}", {
    { L"{count}", ToString(10) },
    { L"{total}", ToString(54) }
 });

The code above will store Hello John in s1 variable and Shown 10 products of 54 in s2 variable. You can use many replacements in keys and params passed to t. All corresponding occurances will be replaced with specified parameters.