Интернационализация


В этой короткой статье объясняется как использовать встроенную возможность интернационализации и добавлять поддержку разных языков в Ваши приложения.



Матрица переводов

Главная концепция в интернационализации приложений - это хранение пар ключ-значение, где ключ - это текст, который нужно перевести, а значение - это перевод(это, конечно же, упрощенное описание). У фреймверка Nitisa есть специальный класс для хранения таких пар. Это хранилище называется матрицей переводов и описывается интерфейсом ITranslate, который реализован классом CTranslate. Вы можете получить доступ к экземпляру интерфейса ITranslate через свойство Application->Translate. У него есть перегруженный метод t, который используется для переводов. Конечно же Вам сначала нужно добавить переведенные значения. Если не сделать этого, то метод t просто вернет значения ключей, которые Вы ему передадите. Для добавления переводов есть 2 метода: Add и Set. Разница между ними заключается в том, что первый просто добавляет данные не проверяя есть ли уже такие в хранилище, а второй не добавляет данные, если они уже присутствуют, однако заменяет их новым значением. Когда Вы первый раз загружаете матрицу переводов в Вашем приложении, используйте метод Add. Это будет работать намного быстрее, особенно если Вы загружаете много текстов. При добавлении переведенных текстов, так же нужно указывать целевой язык, категорию, ключ(обычно он представляет собой текст, который нужно переводить) и переведенное значение. Вы можете помещать все переводы в одну и ту же категорию(например, "app") или разделить их на несколько разных категорий. Это может оказаться полезным в больших приложениях и когда одни и те же ключи должны быть переведены по разному в разных местах. Например, слово "Login" может находится на кнопке и значить "sign in"(войти), а может быть на метке возле поля ввода и означать "user login/name used to authorize"(имя пользователя). В английском языке можно использовать слово "Login" в обоих случаях, однако в других языках, как в Русском, это будет ошибкой. Итак Вы можете использовать один и тот же ключ в обоих элементах управления(значение ключа будет "Login") однако разные категории(например, "auth" и "edit_user").

Использование

Где размещать код для загрузки переводов? Обычно ответ прост: сразу после создания экземпляра класса приложения.

void main()
{
    CApplication app;       // Создание приложения                            // <- Это место, в котором настраивается матрица переводов
    app.CreateForm(&Form1); // Создание формы    // ...
}

Это можно сделать многими способами. Если Вам нужно перевести всего несколько слов/предложений, Вы можете написать их непосредственно в коде. Если же у Вас много текстов Вы можете хранить их в файле/базе данных и вынести заполнение матрицы переводов в отдельную функцию. Даже можно создать свой собственный класс наследуемый от CApplication и выполнить заполнение матрицы переводов в его конструкторе. Выбор за Вами. Вот пример того, как это может быть сделано.

void main()
{
    CApplication app;       // Создание приложения 
    app.Translate->Add(L"ru", L"app", L"Hello user", L"Привет пользователь");
    app.Translate->Add(L"ru", L"app", L"Logout", L"Выход");
    app.Translate->setLanguage(L"ru");
    app.CreateForm(&Form1); // Создание формы 
    // ...
}

Вы уже могли обратить внимание на строчку app.Translate->setLanguage(L"ru");. Она устанавливает текущий язык.

Иногда невозможно задать все переводы сразу после создания приложения. Не волнуйтесь, Вы можете заполнить матрицу переводов в любом месте Вашего приложения. Проблема только в том, что некоторые элементы управления или формы загружают тексты в момент создания и когда Вы заполняете матрицу переводов, они уже могут быть созданы с непереведенными текстами. Если после заполнения матрицы переводов вызвать метод ITranslate->setLanguage(), он так же отправит уведомления всем объектам в Вашем приложении и они загрузят правильные тексты. Однако могут быть ситуации, когда Вы не можете вызвать этот метод либо потому что нужный язык уже установлен, либо по другой причине. В этом случае Вам нужно отправить уведомление вручную. Делайте это методом IApplicationService::SendTranslateChangeNotification() как показано ниже.

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

Какие категории и ключи используются в элементах управления/формах и других объектах фреймверка Вы можете найти на страницах с описанием соответствующих объектов в Справочной системе. Например, посмотрите на справку по форме Color. Она использует категорию FormColor и использует такие ключи как Select Color и Cancel, которые можно перевести. Итак, чтобы перевести заголовок на русский язык, все что нужно - это добавить следующую строчку после создания приложения.

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

Если нужно не перевести, а просто изменить тексты объектов фреймверка, то это можно сделать так:

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

Это изменит заголовок формы выбора цвета с Select Color на Choose Color.

В ключах для перевода также можно указывать параметры, которые будут заменены в дальнейшем на указанные значения. В этом случае нужно использовать метод t, который принимает параметр params. Следующие примеры показывают как его использовать.

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

Вышеприведенный код записывает Hello John(Привет Джон) в переменную s1 и Shown 10 products of 54(Показано 10 продуктов из 54) в переменную s2. Можно использовать множественную замену в t. Все соответствующие ключам вхождения будут заменены на указанное в параметрах значение.