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

来源:developworks 作者:developworks
  

函数 bindtextdomain 的作用是通过给定的 domain 查找路径,可用信息的路径被指定为:

 dirname/locale/category/domainname.mo 

dirname 即为参数 dirname,若参数 dirname 为 NULL,则函数返回程序当前路径值 ( 默认是 /usr/share/locale),若 dirname 值为 "",则返回值为空。locale 即为 locale 名字,category 是 locale 的分类,如 LC_MESSAGES 等。domainname 即为参数 domainname。函数 bind_textdomain_codeset 的功能与 bindtextdomain 相近,因此 glibc 在实现时采用了一个内部函数 set_binding_values 并通过对该函数输入参数的控制分别实现以上 2 个函数。


清单 10. glibc 中实现函数 bindtextdomain
				
 /* intl/bindtextdom.c */ 
 static void 
 set_binding_values (domainname, dirnamep, codesetp) 
     const char *domainname; 
     const char **dirnamep; 
     const char **codesetp; 
 { ... } 

 /* 函数 bindtextdomain */ 
 char * 
 BINDTEXTDOMAIN (domainname, dirname) 
     const char *domainname; 
     const char *dirname; 
 { 
  set_binding_values (domainname, &dirname, NULL); 
  return (char *) dirname; 
 } 

 /* 函数 bind_textdomain_codeset */ 
 char * 
 BIND_TEXTDOMAIN_CODESET (domainname, codeset) 
     const char *domainname; 
     const char *codeset; 
 { 
  set_binding_values (domainname, NULL, &codeset); 
  return (char *) codeset; 
 } 

另外,还有一个可访问 locale 相关信息的重要函数 nl_langinfo,该函数定义于头文件 langinfo.h 中,其作用是通过给定的 item 返回与 locale 相关的信息。


清单 11. 函数 nl_langinfo
				
 #include <langinfo.h> 
 char *nl_langinfo(nl_item item); 

 /* locale/nl_langinfo.c */ 
 char * 
 nl_langinfo (item) 
     nl_item item; 
 { 
  return __nl_langinfo_l (item, _NL_CURRENT_LOCALE); 
 } 





简单示例

通过以上的描述我们大致了解了 Linux 对国际化和本地化的支持,下面我们编写一个获取当前系统时间的小程序来更好的理解函数 setlocale 对整个程序的影响 ( 见 清单 12)。


清单 12. 使用了函数 setlocale 的当前系统时间获取程序
				
 #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 : ¥

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


清单 13. gettext 使用示例
				
 #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)。


清单 14. 执行 gettext 示例程序
				
 $ 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/ 
 $ gcc -Wall gettext-hello.c -o gettext-hello 
 $ LC_ALL=zh_CN.UTF-8 ./ gettext-hello 
你还好吗?


清单 15. catgets 使用示例
				
 #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)。


清单 16. 执行 catgets 示例程序
				
 $ 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 
你还好吗?

时间:2009-12-22 08:44 来源:developworks 作者:developworks 原文链接

好文,顶一下
(2)
50%
文章真差,踩一下
(2)
50%
------分隔线----------------------------


把开源带在你的身边-精美linux小纪念品
无觅相关文章插件,快速提升流量