Skip to content

5. 专题

本章将结合实际的应用场景,来阐述使用Designer开发应用程序时的常用操作,帮助开发者快速入门。本章主要内容包括:

  • 如何实现多国语言。

5.1 如何实现多国语言

AWTK支持多国语言的存储和显示,提供文本翻译、图片翻译等功能,并可以在运行时实时切换语言环境。

5.1.1 如何实现文本翻译

1. 编辑strings.xml实现文本翻译

AWTK采用XML文件(UTF-8)保存文本的各个语言的对应关系,方便程序员和翻译人员进行编辑,实现多国语言互译需要编写strings.xml文件,该文件的具体内容请参阅:awtk/docs/locale.md,这里不详细介绍。

Designer中通过多国语言编辑器可以快速编辑strings.xml文件,添加语言的步骤如下:

  • 点击工具栏的翻译按钮,在多国语言编辑器中打开strings.xml文件,如图5.12所示,若该文件不存在,Designer会自动创建。
  • 点击多国语言翻译器右下角的"中EN+"按钮,弹出添加语言对话框;
  • 在对话框的语言下拉框选择"Chinese",国家/地区下拉框选择"China",点击确定按钮,中国中文(zh_CN)添加完成;
  • 再以相同的方式添加美国英文(en_US),在添加语言对话框的语言下拉框选择"English",国家/地区下拉框选择"United States"。

两种语言添加完成后,多国语言编译器列表上方新增了两列语言标题,分别为中文"Chinese_China"和英文"English_United States"。

项目的语言种类设置完成后,可为每种语言添加相应的翻译文本,步骤如下:

  • 点击多国语言编辑器右下角的"T+"按钮,添加一条翻译文本;
  • 设置原始文本和翻译文本,此处设置原始文本为"awtk";设置中文(zh_CN)为"这是AWTK。";设置英文(en_US)为"This is AWTK.",如下图所示。
  • 保存strings.xml文件并打包资源。

保存strings.xml文件后,Designer会在项目主题目录的strings文件夹中生成多国语言的二进制文件,此处为zh_CN.bin文件和en_US.bin文件,分别对应中国中文和美国英文。

AWTK使用二进制格式保存多国语言文件,为方便计算机处理,每种语言的字符串放在独立的文件中,字符串按升序储存,查询时使用二分法查找。

编辑好strings.xml文件后,以label控件为例,实现字符串翻译的步骤如下:

  • 通过控件列表向UI文件添加label控件 → 选中控件 → 控件属性编辑器 → 值;
  • 点击text属性右侧的是否翻译按钮,当按钮显示翻译图标时表示该控件文本是翻译的;
  • 设置text属性的值为原始文本"awtk";
  • 保存UI文件并打包资源。

编译并运行项目,当项目的语言为中文时,label控件显示中文文本"这是AWTK。",当项目的语言为英文时,label控件显示中文文本"This is AWTK.",如下图所示。

2. 动态文本翻译

若需要翻译的文本是在运行时动态生成的,例如用一个模板根据当前的数据动态生成,可通过多国语言编辑器添加模板翻译文本,然后先调用locale_info_tr()函数获取当前语言的模板,生成真正要显示的字符串,再调用widget_set_text_utf8()函数设置到控件中,代码如下:

c
//Designer安装目录/SDK/awtk/demos/demo_tr_app.c
static ret_t set_locale_value(widget_t* widget, int32_t value) {
  char str[64];

  /* 获取当前语言模板,生成要显示的字符串 */
  const char* format = locale_info_tr(locale_info(), "value is %d");

  /* 将可变参数格式化至字符串中 */
  tk_snprintf(str, sizeof(str), format, value);

  /* 将字符串设置到label控件中*/
  widget_set_text_utf8(widget, str); 

  return RET_OK;
}

/* EVT_LOCALE_CHANGED事件回调函数 */
static ret_t on_locale_changed(void* ctx, event_t* e) { 
  widget_t* win = WIDGET(ctx);
  widget_t* value = widget_lookup(win, "value", TRUE);

  set_locale_value(value, 100); /* 设置翻译文本 */
  ...
  return RET_OK;
}

ret_t application_init() {
  ...
  widget_t* win = window_create(NULL, 0, 0, 0, 0);

  /* 绑定事件回调函数 */
  widget_on(win, EVT_LOCALE_CHANGED, on_locale_changed, win); 
  ...
  return RET_OK;
}

需要注意的是,对于动态翻译的文本,若切换语言时需立即刷新,则须添加EVT_LOCALE_CHANGED事件的处理。

5.1.2 如何实现图片翻译

在一些应用程序中,有些文字是直接绘制在图片上的,所以在切换到不同的语言时,需要加载不同的图片,这时只要在图片名称的最后包含"$locale$"即可,AWTK会自动将"$locale$"替换成当前的语言。以image控件为例,实现图片翻译的如下:

  • 通过资源浏览器向xx文件夹中添加不同语言环境下的图片资源,要求两张图片名称除后缀外完全相同,中文图片名称后缀为"_zh_CN",英文图片名称后缀为"_en_US",此处添加图片"language_zh_CN"和"language_en_US",如下图左侧所示;
  • 通过Designer中的控件列表向home_page文件添加image控件;
  • 设置image控件的image属性为language_$locale$,如下图右侧所示;
  • 保存窗体UI文件并在Designer的工具栏中打包资源。

编译并运行项目,当项目的语言为中文时,image控件显示图片"language_zh_CN",当项目的语言为英文时,image控件显示图片"language_en_US",如图5.17所示。

图片翻译所用的图片名称为"language_$locale$",若当前语言为en_US,加载图片时会按下列顺序查找:language_en_US、language_en、language_,其它资源类似。

5.1.3 如何设置不同语言环境下的默认字体

AWTK中默认的缺省字体是default.ttf,若要设置不同语言环境的默认字体,首先需要在Designer中通过资源浏览器的字体页面添加不同语言的字体文件,步骤如下:

  • 点击资源浏览器字体页面右上角的"+"按钮;
  • 分别添加ttf格式的中文字体文件和英文字体文件,添加完成后点击确定按钮,此处以华文彩云、华文琥珀为例;
  • 在资源浏览器中分别将华文彩云和华文琥珀重命名为"default_zh.ttf"、"default_en.ttf";

添加完字体文件并打包资源后,可以通过以下两种方式设置不同语言环境的默认字体。

1. 切换语言时重新设置默认字体

切换语言时调用system_info_set_default_font()函数设置默认字体,代码如下:

c
/* 设置默认字体为default_zh */
system_info_set_default_font(system_info(), "default_zh");
locale_info_change(locale_info(), language, country); /* 切换语言 */

2. 通过$locale$自动加载默认字体

若不想在每次切换语言时都调用system_info_set_default_font()函数设置默认字体,与图片翻译类似,只需在字体资源文件名称的最后包含"$locale$"即可。

在程序的初始化函数application_init()里调用一次system_info_set_default_font()函数,设置默认字体包含"$locale$",代码如下,效果如下图所示。

c
ret_t application_init(void) {
  /* 设置默认字体包含"$locale$" */
  system_info_set_default_font(system_info(), "default_$locale$");
  widget_t* win = window_open("home_page");
  ...
  return RET_OK;
}

5.1.4 如何在运行时切换语言

在C源文件中,可以调用locale_info_change()函数设置当前的国家和语言,点击中英互译按钮实时切换项目语言,代码如下:

c
//Designer安装目录/SDK/awtk-examples.v2/CleanAir.v2-Demo/src/window_main.c
static ret_t change_locale(const char* str) {
  char country[3];
  char language[3];
  strncpy(language, str, 2);
  strncpy(country, str + 3, 2);
  locale_info_change(locale_info(), language, country); /* 切换语言 */
  return RET_OK;
}

/* 中英互译按钮点击事件的处理函数 */
static ret_t on_language(void* ctx, event_t* e) { 
  widget_t* language_btn = (widget_t*)e->target;
  const char* language = locale_info()->language; /* 获取项目当前语言 */

  if (tk_str_eq(language, "en")) {
    change_locale("zh_CN");
    widget_use_style(language_btn, "language_zh");
  } else {
    change_locale("en_US");
    widget_use_style(language_btn, "language_en");
  }

  return RET_OK;
}

调用locale_info_change()函数会触发EVT_LOCALE_CHANGED事件,在该事件的处理函数中可以更新运行时动态翻译的字符串或者添加其他处理,详细请参见5.2.1章节。