我一直在努力实现一种让我的程序成为双语的方法:用户可以选择是否应该显示法语或英语(在我的情况下)。 我做了大量的研究和谷歌搜索,但我仍然找不到如何做到这一点的好例子:/
我读到了关于gettext的内容,但由于这是针对学校的项目,我们不允许使用外部库(我必须承认,即使我尝试过,我也不知道如何让它工作!)
有人还建议我使用每种语言一个数组,我绝对可以做到这一点,但我发现解决方案非常难看。
我想到的另一种方法是拥有不同的文件,每行都有句子,我可以在需要时检索正确的语言。我想我可以做到这一点,但它似乎也不是最优雅的解决方案。
最后,一位朋友说我可以使用DLL。我已经查到了它,它确实似乎是我能找到的最佳方式之一...问题是我能找到的大部分资源都是用C#和C ++编写的,我仍然不知道我会怎么做要在C中实现:/ 我可以理解它背后的想法,但不知道如何在C中处理它(根本不知道!我不知道如何创建DLL,调用它,从中检索正确的东西或任何> _<)
有人能指出一些我可以使用的有用资源,或者写一段代码来解释工作方式或应该做的事情吗? 这真是太棒了!
提前多多感谢!
(顺便说一句,我使用visual studio 2012和C中的代码)^^
答案 0 :(得分:2)
如果您不能使用第三方库,那么请编写自己的库!不需要dll。
基本思路是每个locale包含一个文件,其中包含文本资源的映射(key = value)。
文件的名称可能类似于
resources_<locale>.txt
其中<locale>
可能类似于en
,fr
,de
等。
当您的程序加注时,它首先读取指定区域设置的资源文件。
最好您必须将每个键/值对存储在一个简单的struct
。
您的读取函数将所有键/值对读入hash table女巫提供了非常好的访问速度。另一种方法是按key
对包含键/值对的数组进行排序,然后在查找时使用binary search(不是最佳选项,但每次迭代所有条目要好得多)。
然后你将不得不编写一个函数get_text
女巫作为参数,要查找的文本资源的键,返回相应的文本作为指定的语言环境读取。你必须处理没有映射的键,最简单的方法是返回键。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define DEFAULT_LOCALE "en"
#define NULL_ARG "[NULL]"
typedef struct localized_text {
char* key;
char* value;
} localized_text_t;
localized_text_t* localized_text_resources = NULL;
int counter = 0;
char* get_text(char*);
void read_localized_text_resources(char*);
char* read_line(FILE*);
void free_localized_text_resources();
int compare_keys(const void*, const void*);
void print_localized_text_resources();
int main(int argc, char** argv)
{
argv++;
argc--;
char* locale = DEFAULT_LOCALE;
if(! *argv) {
printf("No locale provided, default to %s\n", locale);
} else {
locale = *argv;
printf("Locale provided is %s\n", locale);
}
read_localized_text_resources(locale);
printf("\n%s, %s!\n", get_text("HELLO"), get_text("WORLD"));
printf("\n%s\n", get_text("foo"));
free_localized_text_resources();
return 0;
}
char* get_text(char* key)
{
char* text = NULL_ARG;
if(key) {
text = key;
localized_text_t tmp;
tmp.key = key;
localized_text_t* result = bsearch(&tmp, localized_text_resources, counter, sizeof(localized_text_t), compare_keys);
if(result) {
text = result->value;
}
}
return text;
}
void read_localized_text_resources(char* locale)
{
if(locale) {
char localized_text_resources_file_name[64];
sprintf(localized_text_resources_file_name, "resources_%s.txt", locale);
printf("Read localized text resources from file %s\n", localized_text_resources_file_name);
FILE* localized_text_resources_file = fopen(localized_text_resources_file_name, "r");
if(! localized_text_resources_file) {
perror(localized_text_resources_file_name);
exit(1);
}
int size = 10;
localized_text_resources = malloc(size * sizeof(localized_text_t));
if(! localized_text_resources) {
perror("Unable to allocate memory for text resources");
}
char* line;
while((line = read_line(localized_text_resources_file))) {
if(strlen(line) > 0) {
if(counter == size) {
size += 10;
localized_text_resources = realloc(localized_text_resources, size * sizeof(localized_text_t));
}
localized_text_resources[counter].key = line;
while(*line != '=') {
line++;
}
*line = '\0';
line++;
localized_text_resources[counter].value = line;
counter++;
}
}
qsort(localized_text_resources, counter, sizeof(localized_text_t), compare_keys);
// print_localized_text_resources();
printf("%d text resource(s) found in file %s\n", counter, localized_text_resources_file_name);
}
}
char* read_line(FILE* p_file)
{
int len = 10, i = 0, c = 0;
char* line = NULL;
if(p_file) {
line = malloc(len * sizeof(char));
c = fgetc(p_file);
while(c != EOF) {
if(i == len) {
len += 10;
line = realloc(line, len * sizeof(char));
}
line[i++] = c;
c = fgetc(p_file);
if(c == '\n' || c == '\r') {
break;
}
}
line[i] = '\0';
while(c == '\n' || c == '\r') {
c = fgetc(p_file);
}
if(c != EOF) {
ungetc(c, p_file);
}
if(strlen(line) == 0 && c == EOF) {
free(line);
line = NULL;
}
}
return line;
}
void free_localized_text_resources()
{
if(localized_text_resources) {
while(counter--) {
free(localized_text_resources[counter].key);
}
free(localized_text_resources);
}
}
int compare_keys(const void* e1, const void* e2)
{
return strcmp(((localized_text_t*) e1)->key, ((localized_text_t*) e2)->key);
}
void print_localized_text_resources()
{
int i = 0;
for(; i < counter; i++) {
printf("Key=%s value=%s\n", localized_text_resources[i].key, localized_text_resources[i].value);
}
}
与以下资源文件一起使用
resources_en.txt
WORLD=World
HELLO=Hello
resources_de.txt
HELLO=Hallo
WORLD=Welt
resources_fr.txt
HELLO=Hello
WORLD=Monde
生成强>
(1) out.exe /* default */
(2) out.exe en
(3) out.exe de
(4) out.exe fr
<强>输出强>
(1) Hello, World!
(2) Hello, World!
(3) Hallo, Welt!
(4) Hello, Monde!
答案 1 :(得分:0)
gettext是明显的答案,但似乎在你的情况下是不可能的。嗯。如果你真的,真的需要一个自定义解决方案......在这里抛出一个疯狂的想法...
1:创建自定义多语言字符串类型。好处是,如果你愿意,你可以随后轻松添加新语言。你会在#4中看到的缺点。
//Terrible name, change it
typedef struct
{
char *french;
char *english;
} MyString;
2:根据需要定义字符串。
MyString s;
s.french = "Bonjour!";
s.english = "Hello!";
3:实用程序枚举和功能
enum
{
ENGLISH,
FRENCH
};
char* getLanguageString(MyString *myStr, int language)
{
switch(language)
{
case ENGLISH:
return myStr->english;
break;
case FRENCH:
return myStr->french;
break;
default:
//How you handle other values is up to you. You could decide on a default, for instance
//TODO
}
}
4:创建包装函数,而不是使用普通的旧C标准函数。例如,而不是printf
:
//Function should use the variable arguments and allow a custom format, too
int myPrintf(const char *format, MyString *myStr, int language, ...)
{
return printf(format, getLanguageString(myStr, language));
}
这部分是痛苦的:您需要覆盖使用字符串的每个函数来处理自定义字符串。您还可以指定在未指定时使用的全局默认语言变量。
再次:gettext好多了。只有在你真的需要时才实现这个。
答案 2 :(得分:0)
使程序可翻译的主要思想是在所有地方使用文本任何类型的id。然后在显示测试之前,使用id形式获取文本相应的语言表。
示例:强>
而不是写
printf("%s","Hello world");
你写
printf("%s",myGetText(HELLO_WORLD));
通常使用本地语言字符串本身而不是id。 e.g:
printf("%s",myGetText("Hello world"));
最后,myGetText函数通常实现为宏,例如:
printf("%s", tr("Hello world"));
外部解析器(如gettext)可以使用此宏来识别要在源代码中翻译的文本,并将它们作为列表存储在文件中。
myGetText可以按如下方式实现:
std::map<std::string, std::map<std::string, std::string> > LangTextTab;
std::string GlobalVarLang="en"; //change to de for obtaining texts in German
void readLanguagesFromFile()
{
LangTextTab["de"]["Hello"]="Hallo";
LangTextTab["de"]["Bye"]="Auf Wiedersehen";
LangTextTab["en"]["Hello"]="Hello";
LangTextTab["en"]["Bye"]="Bye";
}
const char * myGetText( const char* origText )
{
return LangTextTab[GlobalVarLang][origText ].c_str();
}
请将代码视为伪代码。我没有编译它。还有很多问题需要提及:unicode,线程安全等等...... 我希望这个例子能让你了解如何开始。