This project has been on hold since 2016.
All the data on this site is still available (and will stay available) but not actual anymore.
You might be interested in checking out Dmitry Moskalchuk's portfolio website to learn about his other projects.
Локализация под Android на C/C++? Да, с помощью CrystaX NDK!
20.01.2015 14:40

По определению, хорошее приложение должно быть удобно для пользователя. А удобство использования, помимо всего прочего, означает, что приложение должно разговаривать с пользователем на его родном языке. Но простого перевода слов и предложений недостаточно, разные культуры отличаются друг от друга не только языками, но и, например, способами записи дат, обозначением денежных единиц, правилами преобразования прописных букв в строчные и т.д.. Вся эта информация в программировании собрана в так называемых локалях.

Способы работы с локализованными вводом и выводом описаны в международных стандартах языков программирования ISO C и ISO C++, поэтому обычно достаточно просто следовать стандарту, чтобы должным образом локализовать ваше приложение. К сожалению, этот простой метод не работает на Android для приложений, написанных на C/C++. Библиотека libc на Android (Bionic) не поддерживает локали, поэтому единственный способ использовать локализованный ввод/вывод в коде на C/C++ -- это реализовать локализацию на языке Java и потом использовать ее в коде на C/C++ через JNI. Очевидно, подобный подход вносит существенные накладные расходы во время исполнения программы, но это единственный вариант, если вы используете Google NDK.

В CrystaX NDK мы исправили это досадное упущение и добавили полную поддержку локалей, как описано в стандартах ISO C и ISO C++. Это означает, что если вы используете CrystaX NDK, вы можете использовать стандартный подход к локализации теперь и при разработке под Android.

Давайте рассмотрим несколько примеров такого использования.

Представьте, что у нас есть полноэкранное приложение, использующее OpenGL для отрисовки всего, что происходит на экране, и которому необходимо отобразить текущие дату и время в верхней части экрана. Очевидно, что дата и время должны быть отображены в соответствии с настройками пользователя. Для этого мы должны просто вызвать стандартную функцию setlocale() в начале приложения, после чего последующие вызовы стандартной функции strftime() будут автоматически форматировать дату и время в соответствии с правилами выбранной локали:

#include <locale.h>
#include <time.h>

int fulldatetime(char *buf, size_t bufsize, time_t t)
{
    return strftime(buf, bufsize, "%c", localtime(&t));
}

/* Somewhere at app initialization code */
setlocale(LC_TIME, "en_US.UTF-8");
/* Locale is set, now time formatting would go in that locale */
fulldatetime(buf, sizeof(buf), tm); /*=> Sun Sep 28 02:04:04 2014 */

/* Or */
setlocale(LC_TIME, "fi_FI.UTF-8");
fulldatetime(buf, sizeof(buf), tm); /*=> Su 28 Syy 02:04:04 2014 */

/* Or */
setlocale(LC_TIME, "sv_SE.UTF-8");
fulldatetime(buf, sizeof(buf), tm); /*=> Sön 28 Sep 02:04:04 2014 */

/* Or any other standard locale such as de_DE.UTF-8, ru_RU.UTF-8 etc */

Вот так можно использовать локали в Android. Просто, не правда ли? И, что замечательно, приведенный код будет работать и на других платформах тоже! Другими словами, больше не надо писать отдельную реализацию локализации под Android, просто используйте стандартный подход и собирайте ваш проект под все платформы: Android, iOS, OS X, Windows и т.д.

Однако, некоторым приложениям необходимо показывать одну ту же информацию на разных языках в одно и то же время. Вызов setlocale() в таких случаях не подходит, так как эта функция меняет глобальные установки локали, что оказывает влияние на все приложение. К счастью, CrystaX NDK поддерживает так называемые "расширенные" локали, с помощью которых вы можете передавать нужные локали как параметры в функции форматирования:

#include <locale.h>
#include <time.h>

int fulldatetime(char *buf, size_t bufsize, time_t t, locale_t l)
{
    strftime_l(buf, sizeof(buf), "%c", localtime(&t), l);
}

/* Somewhere at app initialization code */
en_us_l = newlocale(LC_TIME_MASK, "en_US.UTF-8", (locale_t)0);
ru_ru_l = newlocale(LC_TIME_MASK, "ru_RU.UTF-8", (locale_t)0);

/* Now, at any place */
fulldatetime(buf, sizeof(buf), tm, en_us_l); /*=> Sun Sep 28 02:04:04 2014 */
fulldatetime(buf, sizeof(buf), tm, ru_ru_l); /*=> воскресенье, 28 сентября 2014 г. 02:04:04 */

То же самое относится к форматированию денежных значений. К примеру, многие мобильные игры используют покупки игровых ресурсов внутри приложения и указывают цены в валюте пользователя. Такие цены также должны отображаться правильно:

#include <locale.h>
#include <monetary.h>

int price(char *buf, size_t bufsize, double value, locale_t l)
{
    return strfmon(buf, bufsize, l, "%.2n", value);
}

/* Somewhere at app initialization code */
en_us_l = newlocale(LC_TIME_MASK | LC_MONETARY_MASK, "en_US.UTF-8", (locale_t)0);
ru_ru_l = newlocale(LC_TIME_MASK | LC_MONETARY_MASK, "ru_RU.UTF-8", (locale_t)0);

/* Now, at any place */
price(buf, sizeof(buf), 4.99,  en_us_l); /*=> $4.99 */
price(buf, sizeof(buf), 299.0, ru_ru_l); /*=> 299.00 руб. */

Интересно? Тогда начинайте использовать CrystaX NDK прямо сейчас!

Back
Home
Map
Back
Home
Map

Наши авторы: