📄 lang-support.c
字号:
/* TradeClient <http://tradeclient.sourceforge.net> * $Id: lang-support.c,v 1.6 2001/03/20 22:19:33 ttabner Exp $ * * Copyright (C) 1999-2000 Bynari Inc. * Copyright (C) 2001 Project TradeClient * * LGPL * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Library General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library * General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//* Here's the rundown of how it works. Its pretty easy if your using glade. Compile this object into your program and include its h file into every file which will be using multi-national language support. At the begining of int main (), put these lines#ifdef LANG_DEBUG lang_load_external ("lang.db"); lang_startup ();#else lang_generate_list ();#endif and while your in development, define LANG_DEBUG At the end of main, put this #ifdef LANG_DEBUG lang_save_internal ("include/lang-database.h"); lang_save_external ("lang.db"); lang_shutdown ();#endif which will rewrite the database for you. The theory is that under development, the translateable strings will be loaded from a file, if not under development, they are loaded from a hash. language support automatically writes the include/lang-database.h when you call lang_save_interal. You can change the filename to whatever you want, just make sure that it called lang-database.h, or you can change this files includes. Under developement, lang-support will first load translateable strings from either source, or a flatfile. It will create a lang-output directory on lang-shutdown (will not be created if not under developement), and it will write langauge database files for every language, include strings it doesn't know the translations for. You can then send those to people who know how to translate the strings. When you get it back, put the file in the lang-input directory. On lang_startup, it will search for that directory, and read files out of it. If they end with .lang, it will attempt to load them with the native loader, from then on, the translations will be in both external and internal databases and the newly translated strings will not show up in that lang-output/<langdef>.lang. You can also put translateable strings files in the lang-input directory. These files are generated by glade. Just make sure they don't have a .lang extension and everything will be good. I was also thinking about importing the regular .po files, but I don't know exactly how useful that will be This thing compiles perfectly with -ansi and -pedantic, so if your system is not *completely* brain dead *cough*sco*cough* then it should compile fine. Hell, even IF your system IS completely brain dead *achooo!*sco*sniffle*, it should compile just fine.*/#include "lang-support.h"#include "lang-database.h"#ifdef DMALLOC#include <dmalloc.h>#endifint language=0;#define DEVELOPMENT#ifndef MAXLANGUAGES#error "Need MAXLANGUAGES defined in lang-database.h"#endif#ifndef app#define app(l, o) l=lang_llist_append (l, o)#endif#ifndef rem#define rem(l, o) l=lang_llist_remove (l, o)#endif#ifndef nxt#define nxt(o) o=o->next#endif#ifndef prv#define prv(o) o=o->prev#endifllist *lang_trans=NULL;llist *extralangs;llist *deleteables=NULL;int curlang=-1;llist *lang_getlist () { return lang_trans;}/* -ansi didn't like this one, so I made one of my own */char *lang_strdup (char *string) { return strdup( string ) ;}/* Internal Linked List implementation */llist *lang_llist_last (llist *list) { if (list) { while (list->next) list = list->next; } return list; }llist *lang_llist_append (llist *list, void *data) { llist *new_list; llist *last; new_list = (llist *)calloc (1, sizeof (llist)); new_list->data = data; if (list) { last = lang_llist_last (list); last->next = new_list; new_list->prev = last; return list; } return new_list; }llist *lang_llist_remove (llist *list, void *data) { llist *tmp; tmp = list; while (tmp) { if (tmp->data != data) { tmp = tmp->next; } else { if (tmp->prev) tmp->prev->next = tmp->next; if (tmp->next) tmp->next->prev = tmp->prev; if (list == tmp) list = list->next; free (tmp); break; } } return list;}llist *lang_llist_find (llist *list, void *data) { while (list) { if (list->data == data) break; list = list->next; } return list;}llist *lang_llist_find_custom (llist *list, void *data, CompareFunc func) { if (!func) return list; while (list) { if (!func (list->data, data)) return list; list = list->next; } return NULL;}unsigned int lang_llist_length (llist *list) { unsigned int length; length = 0; while (list) { length++; list = list->next; } return length;}void lang_llist_free (llist *list) { while (list) { if (list->prev) { free (list->prev); } if (list->next) { list=list->next; } else { free (list); break; } }}void lang_startup () {#ifdef LANG_DEBUG /* see if we can find the lang-input directory */ DIR *dir=opendir ("./lang-input"); struct dirent *ent; char *tmp=(char *)calloc (25, sizeof (char)); if (!dir) { mkdir ("lang-input", S_IRUSR | S_IWUSR | S_IXUSR); return; } while ((ent=readdir (dir))) { /* portability issue? */ /* see if its a regular file */ struct stat st; sprintf (tmp, "lang-input/%s", ent->d_name); stat (tmp, &st); if (S_ISREG (st.st_mode)) { fprintf (stdout, "Loading database from '%s'\n", ent->d_name); /* does this look native or does it look like a 'po'? */ if (strcasecmp (strrchr (ent->d_name, '.'), ".lang")==0) { lang_load_external_append_only (tmp); } else { lang_merge_glade (tmp); } /* we don't want to delete the files until the end in case the program crashes or we get some other fatal signal */ deleteables=lang_llist_append (deleteables, (void *)lang_strdup (ent->d_name)); } } free (tmp);#endif}char *lang_subst (char *string, char *search, char *replace) { /* general purpose sed s/old/new/g function */ char *tmp=strstr (string, search), *tmp2; char *output; int p=0; if (!string) return NULL; if (!search) return string; if (!replace) while (tmp) { tmp=strstr (tmp + strlen (search), search); p++; } output=(char *)calloc (strlen (string) - (strlen (search) * p) + (strlen (replace) * p) + 5, sizeof (char)); tmp=strstr (string, search); if (!tmp) { free (output); return lang_strdup (string); } memmove (output, string, tmp - string); p = tmp - string; while (tmp) { memmove (output + p, replace, strlen (replace)); p+=strlen (replace); tmp2=strstr (tmp + strlen (search), search); if (tmp2) { memmove (output + p, tmp + strlen (search), tmp2 - tmp - strlen (search)); p+=tmp2 - tmp - strlen (search); } else { memmove (output + p, tmp + strlen (search), strlen (tmp) - strlen (search)); } tmp=tmp2; } return output;}int lang_getlang_num (char *language) { int num; for (num=0;num<MAXLANGUAGES;num++) { if (strcmp (languages[num], language)==0) { return num; } } return -1;}char *lang_getlang () { char *str=getenv ("LANG"); if (!str) { str=lang_strdup ("en"); } else { if (strcmp (str, "C")==0) { str=lang_strdup ("en"); } else { str=lang_strdup (str); } }#ifdef LANG_DEBUG fprintf (stdout, "language: %s\n", str);#endif return str;}/* two custom compare functions for use with llist's */int lang_search_custom (LangNode *node, char *text) { if (node == NULL) return TRUE; if (text == NULL) return TRUE; if (strcmp (node->string, text)==0) return FALSE; return TRUE;}int lang_search_custom2 (LangTrans *node, int language) { if (node == NULL) return TRUE; if (language == -1) return TRUE; if (node->langnum==language) return FALSE; return TRUE;}/* so literal's don't confuse the parser */char *lang_find_nonliteral (char *string, char c) { int i; for (i=1;string[i]!='\0';i++) { if (string[i]==c && string[i-1]!='\\') return string+i; } return NULL;}char *lang_convert_from_literal (char *string) { char *tmp1, *tmp2; return_val_if_fail (string != NULL, NULL); tmp1=lang_subst (string, "\\\"", "\""); /* replace \" with " */ tmp2=lang_subst (tmp1, "\\n", "\n"); /* replace \n with <newline> */ free (tmp1); return tmp2;}/* quick function to see if a string is in the database or not */LangNode *lang_find_node (char *string) { llist *node=lang_llist_find_custom (lang_trans, string, (CompareFunc)lang_search_custom); if (node) return node->data; return NULL;}/* this function needs to be expanded */char *lang_prepare_string (char *string) { char *tmp1, *tmp2; tmp1=lang_subst (string, "\"", "\\\""); tmp2=lang_subst (tmp1, "\n", "\\n"); free (tmp1); return tmp2;}void lang_write_new (FILE *f, char *phrase) { char *tmp; int num; if (phrase) { tmp=lang_prepare_string (phrase); fprintf (f, " {\"%s\",\n", tmp); free (tmp); } else { fprintf (f, " {NULL,\n"); }#ifdef REGENERATION for (num=1;num<REGEN_LEVEL-1;num++)#else for (num=1;num<MAXLANGUAGES-1;num++)#endif fprintf (f, " NULL,\n"); if (phrase) { fprintf (f, " NULL},\n\n"); } else { fprintf (f, " NULL}\n};\n"); }}LangNode *lang_add_native (char *string) { LangNode *node; if ((node=lang_find_node (string))) return node; node=(LangNode *)calloc (1, sizeof (LangNode)); node->string=lang_strdup (string); app (lang_trans, node); return node;}LangTrans *lang_add_trans (LangNode *node, char *string, int langnum) {// int lang; LangTrans *trans; return_val_if_fail (node != NULL, NULL); return_val_if_fail (string != NULL, NULL); if (langnum == -1) { fprintf (stderr, "Attempt to add unsupported language\n"); return NULL; } if (lang_llist_find_custom (node->trans, (void *)langnum, (CompareFunc)lang_search_custom2)) { /* already have this translation for this string */ return NULL; } trans=(LangTrans *)calloc (1, sizeof (LangTrans)); trans->langnum=langnum; trans->string=lang_strdup (string); app (node->trans, trans); return trans;}/*LangLoc *lang_add_location (LangNode *node, char *file, char *func, unsigned int line) { LangLoc *loc; return_val_if_fail (node != NULL, NULL); loc=(LangLoc *)calloc (1, sizeof (LangLoc)); if (file) loc->file=lang_strdup (file); if (func) loc->func=lang_strdup (func); loc->line=line; app (node->locat, loc); return loc;}*/void lang_generate_list () { /* generates the linked list of stuff off the internal database */ int num=0, id; for (num=0;translations[num][0];num++) { LangNode *node=lang_add_native (translations[num][0]); for (id=1;id<MAXLANGUAGES;id++) { if (translations[num][id]) { lang_add_trans (node, translations[num][id], id); } } }}/* the workhorse of the algorithm. This could probably use some optimization */char *lang_xlate (char *file, unsigned int line, char *func, char *string) { LangNode *node=lang_find_node (string); if (curlang==-1) { char *langstr=lang_getlang ();#ifndef DEBUG if (!lang_trans) lang_generate_list ();#endif curlang=lang_getlang_num (langstr); if (curlang==-1 && langstr && strcasecmp (langstr, "C")!=0) { extralangs=lang_llist_append (extralangs, (void *)lang_strdup (langstr)); } else { if (curlang == -1) curlang=0; } free (langstr); } if (!node) { return string; } { llist *seek; LangTrans *trans; for (seek=node->trans;seek;nxt (seek)) { trans=seek->data; if (trans->langnum==curlang) break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -