X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=webcit%2Fgettext.c;h=f055ee5a320f9a7742d3d57ff1ec288f302b542f;hb=8c321fbcc2a64f0d0627562fdf5651442e525ab1;hp=e0978b2c059b040645ccb84b328237463c23cf60;hpb=4760d0fc8089130b066045fa60d312030b0a34e3;p=citadel.git diff --git a/webcit/gettext.c b/webcit/gettext.c index e0978b2c0..f055ee5a3 100644 --- a/webcit/gettext.c +++ b/webcit/gettext.c @@ -1,144 +1,396 @@ -#define _GNU_SOURCE +/* + * $Id$ + */ + #include "webcit.h" #include "webserver.h" #ifdef ENABLE_NLS -static const char *AvailLang[] = { - "de_DE" +#define NUM_LANGS 10 /* how many different locales do we know? */ +#define SEARCH_LANG 20 /* how many langs should we parse? */ + +/* actual supported locales */ +const char *AvailLang[NUM_LANGS] = { + "C", + "en_US", + "de_DE", + "it_IT", + "es_ES", + "en_GB", + "da_DK", + "fr_FR", + "nl_NL", + "pt_BR" }; +const char *AvailLangLoaded[NUM_LANGS]; +long nLocalesLoaded = 0; + +#ifdef HAVE_USELOCALE +locale_t wc_locales[NUM_LANGS]; /**< here we keep the parsed stuff */ +#endif + +/** Keep information about one locale */ typedef struct _lang_pref{ - char lang[16]; - char region[16]; - char *match; - double Priority; + char lang[16]; /**< the language locale string */ + char region[16]; /**< the region locale string */ + long priority; /**< which priority does it have */ + int availability; /**< do we know it? */ + int selectedlang; /**< is this the selected language? */ } LangStruct; -/* TODO: we skip the language weightening so far. */ -/* Accept-Language: 'de-de,en-us;q=0.7,en;q=0.3' */ -/* Accept-Language: de,en-ph;q=0.8,en-us;q=0.5,de-at;q=0.3 */ -void httplang_to_locale(const char *LocaleString) +/* \brief parse browser locale header + * seems as most browsers just do a one after coma value even if more than 10 locales are available. Sample strings: + * opera: + * Accept-Language: sq;q=1.0,de;q=0.9,as;q=0.8,ar;q=0.7,bn;q=0.6,zh-cn;q=0.5,kn;q=0.4,ch;q=0.3,fo;q=0.2,gn;q=0.1,ce;q=0.1,ie;q=0.1 + * Firefox + * Accept-Language: 'de-de,en-us;q=0.7,en;q=0.3' + * Accept-Language: de,en-ph;q=0.8,en-us;q=0.5,de-at;q=0.3 + * Accept-Language: de,en-us;q=0.9,it;q=0.9,de-de;q=0.8,en-ph;q=0.7,de-at;q=0.7,zh-cn;q=0.6,cy;q=0.5,ar-om;q=0.5,en-tt;q=0.4,xh;q=0.3,nl-be;q=0.3,cs;q=0.2,sv;q=0.1,tk;q=0.1 + * \param LocaleString the string from the browser http headers + */ + +void httplang_to_locale(StrBuf *LocaleString) { - char *locale = "C"; - LangStruct wanted_locales[20]; + LangStruct wanted_locales[SEARCH_LANG]; + LangStruct *ls; + int i = 0; int j = 0; - size_t len = strlen(LocaleString); - int nFound = 0; + /* size_t len = strlen(LocaleString); */ + long prio; + int av; + int nBest; int nParts; - const int nAvail = 1; /* Number of members in AvailLang */ - char *search = (char *) malloc(len); - locale_t my_Locale; - locale_t my_Empty_Locale; - - memcpy(search, LocaleString, len); - search[len] = '\0'; - nParts=num_tokens(search,','); - for (i=0; ((ipriority=StrTol(SBuf); } else { - wanted_locales[i].Priority=1.0; + ls->priority=1000; } - /* get the locale part */ - extract_token(&sbuf[0],&buf[0],0,';',16); - /* get the lang part, which should be allways there */ - extract_token(&wanted_locales[i].lang[0],&sbuf[0],0,'-',16); - /* get the area code if any. */ - if (num_tokens(&sbuf[0],'-')>1) { - extract_token(&wanted_locales[i].region[0],&sbuf[0],1,'-',16); + /** get the locale part */ + StrBufExtract_token(SBuf ,Buf, 0, ';'); + /** get the lang part, which should be allways there */ + extract_token(&ls->lang[0], ChrPtr(SBuf), 0, '-', 16); + /** get the area code if any. */ + if (StrBufNum_tokens(SBuf,'-') > 1) { + extract_token(&ls->region[0],ChrPtr(SBuf),1,'-',16); } - else { /* no ara code? use lang code */ - blen=strlen(&wanted_locales[i].lang[0]); - memcpy(&wanted_locales[i].region[0], wanted_locales[i].lang,blen); - wanted_locales[i].region[blen]='\0'; - } /* area codes are uppercase */ - blen=strlen(&wanted_locales[i].region[0]); + else { /** no ara code? use lang code */ + blen=strlen(&ls->lang[0]); + memcpy(&ls->region[0], ls->lang,blen); + ls->region[blen]='\0'; + } /** area codes are uppercase */ + blen=strlen(&ls->region[0]); for (j=0; jregion[j]); + ls->region[j]=(char)chars;/** \todo ?! */ + } + sprintf(&lbuf[0],"%s_%s",&ls->lang[0],&ls->region[0]); + + /** check if we have this lang */ + ls->availability=1; + ls->selectedlang=-1; + for (j=0; jlang[0], AvailLangLoaded[j]); + if ((result<0)&&(resultavailability)){ + ls->availability=result; + ls->selectedlang=j; } + /** match against lang and locale */ + if (0==strcasecmp(&lbuf[0], AvailLangLoaded[j])){ + ls->availability=0; + ls->selectedlang=j; + j=nLocalesLoaded; + } + } + } + + prio=0; + av=-1000; + nBest=-1; + for (i=0; ((iavailability<=0)&& + (avavailability)&& + (priopriority)&& + (ls->selectedlang!=-1)) { + nBest=ls->selectedlang; + av=ls->availability; + prio=ls->priority; + } + } + if (nBest == -1) { + /** fall back to C */ + nBest=0; + } + WC->selected_language=nBest; + lprintf(9, "language found: %s\n", AvailLangLoaded[WC->selected_language]); + FreeStrBuf(&Buf); + FreeStrBuf(&SBuf); +} + +/* TODO: we skip the language weighting so far. */ +/* Accept-Language: 'de-de,en-us;q=0.7,en;q=0.3' */ +/* Accept-Language: de,en-ph;q=0.8,en-us;q=0.5,de-at;q=0.3 */ +//void httplang_to_locale(char *LocaleString) +//{ +// char selected_locale[16]; +// int i, j; +// char lang[64]; +// int num_accept = 0; +// +// lprintf(9, "languageAccept: %s\n", LocaleString); +// +// strcpy(selected_locale, "C"); +// num_accept = num_tokens(LocaleString, ','); +// +// for (i=num_accept-1; i>=0; --i) { +// extract_token(lang, LocaleString, i, ',', sizeof lang); +// +// /* Strip out the weights; we don't use them. Also convert +// * hyphens to underscores. +// */ +// for (j=0; j\n"); + + for (i=0; i < nLocalesLoaded; ++i) { +#ifndef HAVE_USELOCALE + if (strcmp(AvailLangLoaded[i], Lang) == 0) +#endif + wprintf("\n", + ((WC->selected_language == i) ? "selected" : ""), + AvailLangLoaded[i], + AvailLangLoaded[i] + ); } - /* todo: weight */ - if (nFound > 0) { - for (i = 0; i <= nFound; i++) { - for (j = 0; j < nAvail; j++) { - int ret = strncasecmp(&wanted_locales[i].lang[0], - AvailLang[j], - strlen(&wanted_locales[i].lang[0])); - if (!ret) { - locale = (char *) AvailLang[j]; //wanted_locales[i]; - i = nFound + 1; - j = nAvail + 1; - continue; - } - - } + wprintf("\n"); +} + +/** + * \brief Set the selected language for this session. + * \param lang the locale to set. + */ +void set_selected_language(const char *lang) { + int i; + +#ifdef HAVE_USELOCALE + for (i=0; iselected_language = i; } } +#endif +} - len = strlen(locale); - memcpy(search, locale, len); - memcpy(&search[len], ".UTF8", 5); - search[len + 5] = '\0'; - my_Empty_Locale = newlocale(LC_ALL_MASK, NULL, NULL); /* create default locale */ - my_Locale = newlocale(LC_MESSAGES_MASK /*|LC_TIME_MASK FIXME */ , - search, my_Empty_Locale); +/** + * \brief Activate the selected language for this session. + */ +void go_selected_language(void) { +#ifdef HAVE_USELOCALE + wcsession *WCC = WC; + if (WCC->selected_language < 0) return; + uselocale(wc_locales[WCC->selected_language]); /** switch locales */ + textdomain(textdomain(NULL)); /** clear the cache */ +#else + char *language; + + language = getenv("LANG"); + setlocale(LC_MESSAGES, language); +#endif +} - uselocale(my_Locale); - // freelocale(my_Locale); - // freelocale(my_Empty_Locale); - free(search); +/** + * \brief Deactivate the selected language for this session. + */ +void stop_selected_language(void) { +#ifdef HAVE_USELOCALE + uselocale(LC_GLOBAL_LOCALE); /** switch locales */ + textdomain(textdomain(NULL)); /** clear the cache */ +#endif } +void preset_locale(void) +{ +#ifndef HAVE_USELOCALE +#ifdef HAVE_GETTEXT + char *language; + + lprintf(9, "Nailing locale to %s\n", getenv("LANG")); + language = getenv("LANG"); + setlocale(LC_MESSAGES, language); +#endif #endif +} +#ifdef HAVE_USELOCALE + locale_t Empty_Locale; +#endif -/* - // the web browser sends '-', we need '_' +/** + * \brief Create a locale_t for each available language + */ +void initialize_locales(void) { + int i; + char buf[32]; - for (i = 0; i < len; i++) - if (search[i] == '-') - search[i] = '_'; +#ifdef HAVE_USELOCALE + /* create default locale */ + Empty_Locale = newlocale(LC_ALL_MASK, NULL, NULL); +#endif - nFound=i; - nParts=num_tokens(search,','); - if (nParts>0) - { - extract_token(prefers,search, 1,';',len); - extract_token(langs,search, 0,';',len); + for (i = 0; i < NUM_LANGS; ++i) { + if (i == 0) { + sprintf(buf, "%s", AvailLang[i]); // locale 0 (C) is ascii, not utf-8 } - else - { - free(prefers); - prefers=NULL; - memcpy(search, len); - search[len] = '\0'; + else { + sprintf(buf, "%s.UTF8", AvailLang[i]); } - i = 0; - while ( !done && (nFound < 10)) { - if ((search[i] == ',') || (search[i] == ';') || (search[i] == '\0')) - { - if ((search[i] == ';') || (search[i] == '\0')) - done = 1; - search[i] = '\0'; - wanted_locales[nFound] = (char *) &search[j]; - j = i + 1; - nFound++; +#ifdef HAVE_USELOCALE + wc_locales[nLocalesLoaded] = newlocale( + (LC_MESSAGES_MASK|LC_TIME_MASK), + buf, + (((i > 0) && (wc_locales[0] != NULL)) ? wc_locales[0] : Empty_Locale) + ); + if (wc_locales[nLocalesLoaded] == NULL) { + lprintf(1, "Error configuring locale for %s: %s\n", + buf, + strerror(errno) + ); } + else { + lprintf(3, "Configured available locale: %s\n", buf); + AvailLangLoaded[nLocalesLoaded] = AvailLang[i]; + nLocalesLoaded++; + } +#endif + } +} + - i++; +void ShutdownLocale(void) +{ + int i; +#ifdef HAVE_USELOCALE + for (i = 0; i < nLocalesLoaded; ++i) { + if (Empty_Locale != wc_locales[i]) + freelocale(wc_locales[i]); } -*/ +#endif +} + +#else /* ENABLE_NLS */ +/** \brief dummy for non NLS enabled systems */ +void tmplput_offer_languages(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType) { + wprintf("English (US)"); +} + +/** \brief dummy for non NLS enabled systems */ +void set_selected_language(char *lang) { +} + +/** \brief dummy for non NLS enabled systems */ +void go_selected_language(void) { +} + +/** \brief dummy for non NLS enabled systems */ +void stop_selected_language(void) { +} + +void preset_locale(void) +{ +} +#endif /* ENABLE_NLS */ + + +void TmplGettext(StrBuf *Target, int nTokens, WCTemplateToken *Tokens) +{ + StrBufAppendBufPlain(Target, _(Tokens->Params[0]->Start), -1, 0); +} + + +/* + * Returns the language currently in use. + * This function returns a static string, so don't do anything stupid please. + */ +const char *get_selected_language(void) { +#ifdef ENABLE_NLS +#ifdef HAVE_USELOCALE + return AvailLang[WC->selected_language]; +#else + return "en" +#endif +#else + return "en" +#endif +} + +void +InitModule_GETTEXT +(void) +{ + RegisterNamespace("LANG:SELECT", 0, 0, tmplput_offer_languages, CTX_NONE); +}