Локализация под 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

Наши авторы: