C中控制台应用程序中的双语程序

时间:2013-04-24 18:36:56

标签: c dll

我一直在努力实现一种让我的程序成为双语的方法:用户可以选择是否应该显示法语或英语(在我的情况下)。 我做了大量的研究和谷歌搜索,但我仍然找不到如何做到这一点的好例子:/

我读到了关于gettext的内容,但由于这是针对学校的项目,我们不允许使用外部库(我必须承认,即使我尝试过,我也不知道如何让它工作!)

有人还建议我使用每种语言一个数组,我绝对可以做到这一点,但我发现解决方案非常难看。

我想到的另一种方法是拥有不同的文件,每行都有句子,我可以在需要时检索正确的语言。我想我可以做到这一点,但它似乎也不是最优雅的解决方案。

最后,一位朋友说我可以使用DLL。我已经查到了它,它确实似乎是我能找到的最佳方式之一...问题是我能找到的大部分资源都是用C#和C ++编写的,我仍然不知道我会怎么做要在C中实现:/ 我可以理解它背后的想法,但不知道如何在C中处理它(根本不知道!我不知道如何创建DLL,调用它,从中检索正确的东西或任何> _<)

有人能指出一些我可以使用的有用资源,或者写一段代码来解释工作方式或应该做的事情吗? 这真是太棒了!

提前多多感谢!

(顺便说一句,我使用visual studio 2012和C中的代码)^^

3 个答案:

答案 0 :(得分:2)

如果您不能使用第三方库,那么请编写自己的库!不需要dll。

基本思路是每个locale包含一个文件,其中包含文本资源的映射(key = value)。

文件的名称可能类似于

resources_<locale>.txt

其中<locale>可能类似于enfrde等。

当您的程序加注时,它首先读取指定区域设置的资源文件。

最好您必须将每个键/值对存储在一个简单的struct

您的读取函数将所有键/值对读入hash table女巫提供了非常好的访问速度。另一种方法是按key对包含键/值对的数组进行排序,然后在查找时使用binary search(不是最佳选项,但每次迭代所有条目要好得多)。

然后你将不得不编写一个函数get_text女巫作为参数,要查找的文本资源的键,返回相应的文本作为指定的语言环境读取。你必须处理没有映射的键,最简单的方法是返回键。

以下是一些示例代码(使用qsortbsearch):

#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,线程安全等等...... 我希望这个例子能让你了解如何开始。