【C語言】如何用代碼設置多國語言

寫在前面的話:

  1. 版權聲明:本文爲博主原創文章,轉載請註明出處!
  2. 博主是一個小菜鳥,並且非常玻璃心!如果文中有什麼問題,請友好地指出來,博主查證後會進行更正,啾咪~~
  3. 每篇文章都是博主現階段的理解,如果理解的更深入的話,博主會不定時更新文章。
  4. 本文最後更新時間:2020.4.29

正文開始

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") 替換,兩者效果相同。

參考

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章