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原生本地化? 是的, 通过CrystaX NDK!
2015.01.20 14:40

好的应用必定要有好的用户体验. 首先这意味着应用程序应该支持用户所熟知的语言. 但是仅仅翻译文字和段落是远远不够的 - 不同语言文化之间还有很多其他不同元素, 包括日期格式, 货币, 格式化规则等等. 这些具体的信息都以 locales 来界定.

ISO C和ISO C++标准定义了locale相关的输入输出操作规范, 所以通常只要按照标准正确本地化你的应用就够了. 不幸的是, 这种方法不适用于Android C/C++. Android libc (Bionic)不支持locales, 所以在native代码中使用本地化输入输出的唯一方法是通过JNI调用Java本地化实现. 显然这种方法增加了显著的运行时开销, 但这是你使用谷歌Android NDK的唯一选择.

CrystaX NDK中, 我们处理了这一令人遗憾的遗漏, 添加了完整实现的ISO C和ISO C++标准的locales. 这意味着通过使用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, iOS, OS X, Windows, 等等.

然后有些应用程序需要同时支持相同内容的多种不同语言展示. 调用setlocale()在这种情况下不是一个好办法, 因为setlocale()是全局设置, 影响整个应用程序. 幸运的是, CrystaX NDK提供了所谓的"locales扩展", 允许你通过参数指定locale结果:

#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

Our contributors: