首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

浅析 Linux 的国际化与本地化机制(4)

浅析 Linux 的国际化与本地化机制(4)

简单示例通过以上的描述我们大致了解了 Linux 对国际化与本地化的支持,下面我们编写一个获取当前系统时间的小程序来更好的理解函数 setlocale 对整个程序的影响 ( 见 )。
清单 12. 使用了函数 setlocale 的当前系统时间获取程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <time.h>
#include <locale.h>
#include <stdio.h>

#define SIZE 80

int main (int argc, char *argv[])
{
   time_t now;
   struct tm *timeinfo;
   struct lconv *lc;
   char buffer[SIZE];

   setlocale (LC_ALL, "");
   printf ("LC_TIME = %s\n", setlocale (LC_TIME, NULL));
   printf ("LC_MONETARY = %s\n", setlocale (LC_MONETARY, NULL));

   time (&now);
   timeinfo = localtime (&now);

   strftime (buffer, SIZE, "%c", timeinfo);
   printf ("Date : %s\n", buffer);

   lc = localeconv();
   printf ("Currency symbol : %s\n", lc->currency_symbol);

   return 0;
}

$ gcc -Wall locale-time.c -o locale-time
$ LC_ALL=zh_CN.UTF-8 ./locale-time
LC_TIME = zh_CN.UTF-8
LC_MONETARY = zh_CN.UTF-8
Date : 2009 年 11 月 05 日 星期四 19 时 47 分 46 秒
Currency symbol : ¥




在 中,我们不仅展示了 setlocale 函数的 "" 和 NULL 这两个特殊参数值的使用,还使用了 lconv 这个数据结构用于打印与区域相一致的货币符号 (lconv 这个有关数字和货币规则信息的结构体及相关函数 localeconv 被定义在头文件 locale.h 中,与 locale 中的 LC_NUMERIC 和 LC_MONETARY 相关 )。在程序执行时,我们动态的修改了 locale 环境变量的值以此来更好的观察 setlocale 函数对程序的影响 ( 如前述使用 date 命令时一样,见 )。在没有调用函数 setlocale 的程序中,程序将使用默认环境值 "C" 或 "POSIX"。由于我们在上面提过 glibc 提供了两组不同的接口实现程序的国际化与本地化,为了更好的理解这两种方式,我们在下面分别进行展示 ( 见 和 )。
清单 13. gettext 使用示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <locale.h>
#include <libintl.h>
#include <stdio.h>

#define PACKAGE "gettext-hello"
#define LOCALEDIR "po"
#define N_(msgid) gettext(msgid)

int main (int argc, char *argv[])
{
   setlocale (LC_CTYPE, "zh_CN.UTF-8");
   setlocale (LC_MESSAGES, "zh_CN.UTF-8");

   bindtextdomain (PACKAGE, LOCALEDIR);
   textdomain (PACKAGE);

   /* Translators: 这里仅是一个注释 */
   printf (N_("Are you ok?\n"));

   return 0;
}




我们指定使用 locale 名字为 "zh_CN.UTF-8" 以此方便我们建立目录进行测试,但是更通常的做法是使用 "" 作为参数值使程序适应不同的语言 ( 区域 ) 环境。另外,我们需要为这个简单的程序做一个翻译,并生成一个可用的二进制翻译文件。我们使用由 GNU gettext 提供的工具 xgettext 及 msgfmt 来完成翻译档的生成,但这仅是用于制作、维护 PO (Portable Object) 和 MO (Machine Object) 文件的部分工具集 ( 见 )。
清单 14. 执行 gettext 示例程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ xgettext --add-comments  --keyword=N_ gettext-hello.c -o \
> gettext-hello.pot --from-code=UTF-8
$ cp gettext-hello.pot gettext-hello.po
$ cat locale-hello.po
...
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
...
#. Translators: 这里仅是一个注释
#: locale-hello.c:23
msgid "Are you ok?\n"
msgstr "你还好吗? \n"

$ mkdir -p po/zh_CN.UTF-8/LC_MESSAGES/
$ msgfmt gettext-hello.po -o gettext-hello.mo
$ mv gettext-hello.mo po/zh_CN.UTF-8/LC_MESSAGES/
$ unset LANGUAGE
$ gcc -Wall gettext-hello.c -o gettext-hello
$ LC_ALL=zh_CN.UTF-8 ./ gettext-hello
你还好吗?




清单 15. catgets 使用示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <nl_types.h>
#include <locale.h>
#include <stdio.h>

#define CATALOG_NAME "catgets-hello.cat"

int main (int argc, char *argv[])
{
   nl_catd catd;
   setlocale (LC_ALL, "");
   printf ("LC_MESSAGES = %s\n", setlocale (LC_MESSAGES, NULL));

   catd = catopen (CATALOG_NAME, NL_CAT_LOCALE);
   if(catd == (nl_catd) -1) {
       perror("catopen");
       return 1;
   }

   int set_no=11;
   int msg_id=14;
   printf("%s\n", catgets (catd, set_no, msg_id, "Are you OK?"));

   if(catclose(catd) < 0) {
       perror ("catclose");
       return 1;
   }

   return 0;
}




我们在 catgets 示例代码中加上了错误处理,但这仅是为了更好的展示。通常情况下这是不需要的,因为我们应尽量使程序运行下去而不是中断。在编辑完程序所需的翻译档后,我们执行这个简单的 catgets 示例 ( 见 )。
清单 16. 执行 catgets 示例程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ cat catgets-hello.msg
...
$set 11
14 你还好吗?
15 I am fine,thanks.
...

$ gencat catgets-hello.msg -o catgets-hello.cat
$ mv catgets-hello.cat  po/zh_CN.UTF-8/LC_MESSAGES/
$ gcc -Wall catgets-hello.c -o catgets-hello
$ export NLSPATH=po/%L/LC_MESSAGES/%N
$ LC_ALL=zh_CN.UTF-8 ./ catgets-hello
LC_MESSAGES = zh_CN.UTF-8
你还好吗?




我们使用命令 gencat 生成程序所需的二进制翻译档并通过 NLSPATH 指定该文件存放的位置。若不指定该变量,默认的位置将是如下所示。
[1] prefix/share/locale/%L/%N
[2] prefix/share/locale/%L/LC_MESSAGES/%N
其中 %L 用于指定 locale 名字,%N 为文件名。对于上面几个示例及命令,更好的执行方式是通过 strace 等调试工具进行跟进,这不仅能熟悉相关函数的作用,并可更好的理解 Linux 国际化与本地化机制。
返回列表