2016-10-28 54 views
0

我試圖找出爲什麼GNU的gettext的行爲是不喜歡strftimeprintf當談到本地化。我從A到Z閱讀整個手冊,但這些例子非常簡單。我已經將問題簡化爲一個簡單的C程序。不穩定本地化行爲的gettext相比STRFTIME或printf的

的任務是通過用戶輸入來切換區域設置在應用程序中接收的局部文件輸出。

我的語言環境:

LANG=de_DE.UTF-8 
LC_CTYPE="de_DE.UTF-8" 
LC_COLLATE="de_DE.UTF-8" 
LC_TIME="de_DE.UTF-8" 
LC_NUMERIC="de_DE.UTF-8" 
LC_MONETARY="de_DE.UTF-8" 
LC_MESSAGES="de_DE.UTF-8" 
LC_ALL= 

考慮這個C示例:

#include <stdio.h> 
#include <stdlib.h> 
#include <locale.h> 
#include <time.h> 
#include <math.h> 
#include "my-i18n.h" 

#define PI acos(-1.0) 

static char *locales[] = { 
     "de_DE.UTF-8", 
     "ru_RU.UTF-8", 
     "he_IL.UTF-8", 
     "es_ES.UTF-8", 
     "C", 
}; 

void localize(char *locale, struct tm *time) { 
     printf("==============================================================\n"); 
     printf("Passed locale: %s\n", locale); 
     char *setlocale_out = setlocale(LC_ALL, locale); 
     printf("Set locale: %s\n", setlocale_out); 

     char buffer[80]; 
     strftime(buffer, sizeof(buffer), "%c", time); 
     printf("Localized time: %s\n", buffer); 

     printf("Get rational, π: %f\n", PI); 

     printf(_("Hello World!\n")); 
     printf(_("Goodbye!\n")); 
} 

int main(void) { 
     time_t rawtime = time(NULL); 
     struct tm *time; 
     localtime(&rawtime); 
     time = localtime(&rawtime); 

     bindtextdomain("my-i18n", LOCALEDIR); 
     textdomain("my-i18n"); 
     int i; 
     for (i = 0; i < sizeof(locales)/sizeof(locales[0]); i++) { 
       localize(locales[i], time); 
     } 

     return EXIT_SUCCESS; 
} 

,其輸出:

============================================================== 
Passed locale: de_DE.UTF-8 
Set locale: de_DE.UTF-8 
Localized time: Fr 28 Okt 11:44:24 2016 
Get rational, π: 3,141593 
Setting LANG=de_DE.UTF-8 
Hallo Welt! 
Tschüß! 
============================================================== 
Passed locale: ru_RU.UTF-8 
Set locale: ru_RU.UTF-8 
Localized time: пятница, 28 октября 2016 г. 11:44:24 
Get rational, π: 3,141593 
Setting LANG=ru_RU.UTF-8 
Hallo Welt! 
Tschüß! 
============================================================== 
Passed locale: he_IL.UTF-8 
Set locale: he_IL.UTF-8 
Localized time: CEST 11:44:24 2016 אוק 28 ו' 
Get rational, π: 3.141593 
Setting LANG=he_IL.UTF-8 
Hallo Welt! 
Tschüß! 
============================================================== 
Passed locale: es_ES.UTF-8 
Set locale: es_ES.UTF-8 
Localized time: vie 28 oct 11:44:24 2016 
Get rational, π: 3,141593 
Setting LANG=es_ES.UTF-8 
Hallo Welt! 
Tschüß! 
============================================================== 
Passed locale: C 
Set locale: C 
Localized time: Fri Oct 28 11:44:24 2016 
Get rational, π: 3.141593 
Setting LANG=C 
Hallo Welt! 
Tschüß! 

正如你所看到的,strftimeprintf做了什麼我的預期,但gettext只考慮我的外部區域設置。在Google和SO搜索之後,我發現每setlocale之後必須執行bindtextdomain和/或textdomain。此外,我必須執行putenv("LANG=...")強制gettext工作。

修改C代碼:

#include <stdio.h> 
#include <stdlib.h> 
#include <locale.h> 
#include <time.h> 
#include <math.h> 
#include "my-i18n.h" 

#define PI acos(-1.0) 

static char *locales[] = { 
     "de_DE.UTF-8", 
     "ru_RU.UTF-8", 
     "he_IL.UTF-8", 
     "es_ES.UTF-8", 
     "C", 
}; 

void localize(char *locale, struct tm *time) { 
     printf("==============================================================\n"); 
     printf("Passed locale: %s\n", locale); 
     char *setlocale_out = setlocale(LC_ALL, locale); 
     printf("Set locale: %s\n", setlocale_out); 

     char buffer[80]; 
     strftime(buffer, sizeof(buffer), "%c", time); 
     printf("Localized time: %s\n", buffer); 

     printf("Get rational, π: %f\n", PI); 

     printf("Setting LANG=%s\n", locale); 
     setenv("LANG", locale, 1); 

     bindtextdomain("my-i18n", LOCALEDIR); 
     textdomain("my-i18n"); 
     printf(_("Hello World!\n")); 
     printf(_("Goodbye!\n")); 
} 

int main(void) { 
     time_t rawtime = time(NULL); 
     struct tm *time; 
     localtime(&rawtime); 
     time = localtime(&rawtime); 

     int i; 
     for (i = 0; i < sizeof(locales)/sizeof(locales[0]); i++) { 
       localize(locales[i], time); 
     } 

     return EXIT_SUCCESS; 
} 

和輸出:

============================================================== 
Passed locale: de_DE.UTF-8 
Set locale: de_DE.UTF-8 
Localized time: Fr 28 Okt 11:50:33 2016 
Get rational, π: 3,141593 
Setting LANG=de_DE.UTF-8 
Hallo Welt! 
Tschüß! 
============================================================== 
Passed locale: ru_RU.UTF-8 
Set locale: ru_RU.UTF-8 
Localized time: пятница, 28 октября 2016 г. 11:50:33 
Get rational, π: 3,141593 
Setting LANG=ru_RU.UTF-8 
Привет мир! 
Пока! 
============================================================== 
Passed locale: he_IL.UTF-8 
Set locale: he_IL.UTF-8 
Localized time: CEST 11:50:33 2016 אוק 28 ו' 
Get rational, π: 3.141593 
Setting LANG=he_IL.UTF-8 
Hello World! 
Goodbye! 
============================================================== 
Passed locale: es_ES.UTF-8 
Set locale: es_ES.UTF-8 
Localized time: vie 28 oct 11:50:33 2016 
Get rational, π: 3,141593 
Setting LANG=es_ES.UTF-8 
¡Hola mundo! 
¡Adios! 
============================================================== 
Passed locale: C 
Set locale: C 
Localized time: Fri Oct 28 11:50:33 2016 
Get rational, π: 3.141593 
Setting LANG=C 
Hello World! 
Goodbye! 

有人能解釋一下這個 「怪異」 的行爲?

編輯:我曾提出它在郵件列表上:http://lists.gnu.org/archive/html/bug-gettext/2016-11/msg00002.html

回答

0

你需要一個setlocale()電話後打電話到bindtextdomain()的主要原因,是緩存

如果每個gettext()通話中被檢查的環境變量,這將是非常緩慢的。今天的機器可能不會引人注目,但它過去很重要。相反,當您發出bindtextdomain()調用並且緩存結果以提高效率時,(區域設置)查找完成。

在實踐中,也有..疣。特別是,LANGUAGE環境變量會影響每個gettext()調用。此外,gettext的不 支持線程特定的語言環境中(通過uselocale() GNU擴展) - 在Linux中,使用的glibc 2.4或更高版本(2006年發佈)時,自2013年前後在MacOS上/ Mac OSX版。 (編輯:我開始之前,使用gettext的方式,只是沒能跟上,我做了假設我不應該道歉。)由於gettext的最初版本是在1990年,和很多東西都有在當時和現在之間改變,你可以考慮這個歷史包袱,甚至是一個錯誤。

+0

嗯..但'putenv'怎麼樣。即使使用'bindtextdomain',如果沒有調用'putenv',它也不起作用。這些文檔對它沒有什麼幫助。 –

+0

@ Michael-O:我認爲這是一個bug;我隱約記得幾年前在某個地方看到了一些討論(可能是[bug-gettext](http://lists.gnu.org/archive/html/bug-gettext/)郵件列表或musl郵件列表),與我提到的那些實用疣有關。順便說一下,爲什麼不使用'setenv(「LANG」,locale,1)'而不是'putenv()'? –

+0

這只是我在SO上找到的示例代碼。我會改變我的問題。謝謝。 –