【C语言】如何用代码设置多国语言

写在前面的话:

  1. 版权声明:本文为博主原创文章,转载请注明出处!
  2. 博主是一个小菜鸟,并且非常玻璃心!如果文中有什么问题,请友好地指出来,博主查证后会进行更正,啾咪~~
  3. 每篇文章都是博主现阶段的理解,如果理解的更深入的话,博主会不定时更新文章。
  4. 本文最后更新时间:2020.5.20

正文开始

1. 举个例子

myLang.c

#include <stdio.h>
#include <libintl.h>
#include <locale.h>

#define _(string) gettext(string)

int main()
{
	bindtextdomain("myLang", "Lang/locale");
	textdomain("myLang");

	setlocale(LC_ALL, "zh_CN.UTF-8");

	char notice[200] = {0};
	sprintf(notice, "%s", _("hello world"));
	printf("%s\n", notice);

	return 0;
}

编译并执行:

gcc myLang.c -o myLang    #编译
./myLang                  #执行

运行结果:

你好,世界

目录结构:
在这里插入图片描述

2. 函数详解

2.1 bindtextdomain() 函数

bindtextdomain() - 设置文本域目录

函数声明如下:

#include <libintl.h>

char * bindtextdomain (const char * domainname, const char * dirname);

文本域文件就是 .mo文件,这个文件是二进制的(基于性能方面的考虑),在开发多语言软件中会用到。

例如: 在英文环境下,程序打印 “hello world”,而在中文环境中需要打印 “你好,世界”,这时需要将翻译放在 .po 文件中,再由 .po 文件生成 .mo 文件。

.po文件格式如下:

msgid "hello world"
msgstr "你好,世界"

其中 msgid 为原文,msgstr 为翻译内容。

.po 文件生成 .mo 文件命令:

msgfmt xxx.po -o xxx.mo

bindtextdomain() 有两个参数:

  1. domainname:域名,即指明 .mo 文件将应用在哪个工程中,域名必须是非空字符串。
    例如:示例工程叫 myLang,则 domainname 也为 “myLang”。
  2. dirname:locale 目录的路径,即在这个指定的路径下寻找 .mo 文件,相对路径或绝对路径都可以。

完整存放 .mo 文件的路径一般为 dirname/locale/category/domainname.mo,其中:

  • dirname:是我们设置的第二个参数,指定 locale 目录的路径。
  • locale:指语言环境名称。下面有各语言目录,如:zh_CN。设置包含 LC_MESSAGES 分类 (catalog) 的 locale 目录,程序的 .mo 文件保存在其下的 LC_MESSAGES 目录中。
  • category:是语言环境方面,例如 LC_MESSAGES,LC_MESSAGES 是 locale 的一个分类 (catalog)。

例如,示例程序完整的 .mo 文件路径:

[程序当前目录]/Lang/locale/zh_CN/LC_MESSAGES/myLang.mo

而示例代码为:

bindtextdomain("myLang", "Lang/locale");

2.2 setlocale() 函数

setlocale() - 设定locale

函数声明如下:

#include <locale.h>

char *setlocale(int category, const char *locale);

LC_ALL适用于所有语言环境

示例代码为:

setlocale(LC_ALL, "zh_CN.UTF-8");  //设置为中文环境

2.3 textdomain() 函数

textdomain() - 设置文本域文件

函数声明如下:

#include <libintl.h>

char * textdomain (const char * domainname);

该函数用于设置需要使用的文本域。即设置后来使用 gettext() 函数时的 domain。

即使用顺序为:

bindtextdomain 指定文本域
textdomain 设置文本域
gettext 进行翻译替换

如果程序需要用到多个 .mo 文件,那么需要多次执行 bindtextdomain() 函数,再用 textdomain() 来指定当前需要使用哪一个。

示例代码为:

textdomain("myLang");

2.4 gettext() 函数

函数声明如下:

#include <libintl.h>

char * gettext (const char * msgid);

将程序中的 msgid 替换为 .mo 中的 msgstr,并返回 msgstr。简单讲就是根据原文找到并返回翻译的内容。

例如:

gettext("hello world");    //以中文为例,返回“你好,世界”

示例代码:

sprintf(notice, "%s", _("hello world"));
sprintf(notice, "%s", gettext("hello world"));

示例代码中使用了宏 #define _(string) gettext(string),这样可以简化接下来的写法,即工程中的 gettext("xxx") 可以用 _("xxx") 替换,两者效果相同。

3. 关于翻译的内容

关于翻译,还有一个需要注意的问题:

程序中需要翻译的字符串,必须是唯一的,但是由于程序比较大,要翻译的东西很多,而有些单词,有不同的意思。比如 “note”,有时要翻译成“笔记”,有时又要翻译成“便笺”,这个该如何解决呢?

需要解释的是,翻译的时候并不是针对字符串,而是每个字符串的id

以 note 为例,可以设置两个 msgid:“note_1” 和 “note_2”,然后创建 po 文件时,就可以分别翻译:

msgid "note_1"
msgstr "笔记"

msgid "note_2"
msgstr "便笺"

现在很多开源软件都是这么做的,这样比较清晰,不会重复,但是也有缺点,就是英文环境也需要翻译一遍,会有点麻烦。

参考

bindtextdomain(3) - Linux man page
gettext(3) - Linux man page
textdomain(3) - Linux man page
setlocale(3) - Linux man page
msgfmt(1) - Linux man page
其他参考链接

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值