7 #define SEARCH_LANG 20 /* how many langs should we parse? */
10 /* actual supported locales */
11 const char *AvailLang[] = {
28 const char **AvailLangLoaded;
29 long nLocalesLoaded = 0;
32 locale_t *wc_locales; /**< here we keep the parsed stuff */
35 /** Keep information about one locale */
36 typedef struct _lang_pref{
37 char lang[16]; /**< the language locale string */
38 char region[16]; /**< the region locale string */
39 long priority; /**< which priority does it have */
40 int availability; /**< do we know it? */
41 int selectedlang; /**< is this the selected language? */
44 /* \brief parse browser locale header
45 * seems as most browsers just do a one after coma value even if more than 10 locales are available. Sample strings:
47 * 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
49 * Accept-Language: 'de-de,en-us;q=0.7,en;q=0.3'
50 * Accept-Language: de,en-ph;q=0.8,en-us;q=0.5,de-at;q=0.3
51 * 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
52 * \param LocaleString the string from the browser http headers
55 void httplang_to_locale(StrBuf *LocaleString, wcsession *sess)
57 LangStruct wanted_locales[SEARCH_LANG];
62 /* size_t len = strlen(LocaleString); */
70 nParts=StrBufNum_tokens(LocaleString,',');
71 for (i=0; ((i<nParts)&&(i<SEARCH_LANG)); i++)
85 ls=&wanted_locales[i];
87 StrBufExtract_token(Buf,LocaleString, i,',');
88 /** we are searching, if this list item has something like ;q=n*/
89 if (StrBufNum_tokens(Buf,'=')>1) {
91 StrBufExtract_token(SBuf,Buf, 1,'=');
92 sbuflen=StrLength(SBuf);
93 for (k=0; k<sbuflen; k++)
94 if (ChrPtr(SBuf)[k]=='.')
95 StrBufPeek(SBuf, NULL, k, '0');
96 ls->priority=StrTol(SBuf);
101 /** get the locale part */
102 StrBufExtract_token(SBuf ,Buf, 0, ';');
103 /** get the lang part, which should be allways there */
104 extract_token(&ls->lang[0], ChrPtr(SBuf), 0, '-', 16);
105 /** get the area code if any. */
106 if (StrBufNum_tokens(SBuf,'-') > 1) {
107 extract_token(&ls->region[0],ChrPtr(SBuf),1,'-',16);
109 else { /** no ara code? use lang code */
110 blen=strlen(&ls->lang[0]);
111 memcpy(&ls->region[0], ls->lang,blen);
112 ls->region[blen]='\0';
113 } /** area codes are uppercase */
114 blen=strlen(&ls->region[0]);
115 for (j=0; j<blen; j++)
117 int chars=toupper(ls->region[j]);
118 ls->region[j]=(char)chars;/** \todo ?! */
120 sprintf(&lbuf[0],"%s_%s",&ls->lang[0],&ls->region[0]);
122 /** check if we have this lang */
125 for (j=0; j<nLocalesLoaded; j++) {
127 /** match against the LANG part */
128 result=strcasecmp(&ls->lang[0], AvailLangLoaded[j]);
129 if ((result<0)&&(result<ls->availability)){
130 ls->availability=result;
133 /** match against lang and locale */
134 if (0==strcasecmp(&lbuf[0], AvailLangLoaded[j])){
145 for (i=0; ((i<nParts)&&(i<SEARCH_LANG)); i++) {
146 ls=&wanted_locales[i];
147 if ((ls->availability<=0)&&
148 (av<ls->availability)&&
149 (prio<ls->priority)&&
150 (ls->selectedlang!=-1)) {
151 nBest=ls->selectedlang;
157 /** fall back to C */
160 sess->selected_language=nBest;
161 lprintf(9, "language found: %s\n", AvailLangLoaded[WC->selected_language]);
167 * \brief show the language chooser on the login dialog
168 * depending on the browser locale change the sequence of the
171 void tmplput_offer_languages(StrBuf *Target, WCTemplputParams *TP)
174 #ifndef HAVE_USELOCALE
175 char *Lang = getenv("LANG");
182 if (nLocalesLoaded == 1) {
183 wprintf("<p>%s</p>", AvailLangLoaded[0]);
187 wprintf("<select name=\"language\" id=\"lname\" size=\"1\">\n");
189 for (i=0; i < nLocalesLoaded; ++i) {
190 #ifndef HAVE_USELOCALE
191 if (strcmp(AvailLangLoaded[i], Lang) == 0)
193 wprintf("<option %s value=%s>%s</option>\n",
194 ((WC->selected_language == i) ? "selected" : ""),
200 wprintf("</select>\n");
204 * \brief Set the selected language for this session.
205 * \param lang the locale to set.
207 void set_selected_language(const char *lang) {
208 #ifdef HAVE_USELOCALE
210 for (i=0; i<nLocalesLoaded; ++i) {
211 if (!strcasecmp(lang, AvailLangLoaded[i])) {
212 WC->selected_language = i;
219 * \brief Activate the selected language for this session.
221 void go_selected_language(void) {
222 #ifdef HAVE_USELOCALE
224 if (WCC->selected_language < 0) return;
225 uselocale(wc_locales[WCC->selected_language]); /** switch locales */
226 textdomain(textdomain(NULL)); /** clear the cache */
230 language = getenv("LANG");
231 setlocale(LC_MESSAGES, language);
236 * \brief Deactivate the selected language for this session.
238 void stop_selected_language(void) {
239 #ifdef HAVE_USELOCALE
240 uselocale(LC_GLOBAL_LOCALE); /** switch locales */
241 textdomain(textdomain(NULL)); /** clear the cache */
245 #ifdef HAVE_USELOCALE
246 locale_t Empty_Locale;
250 * \brief Create a locale_t for each available language
252 void initialize_locales(void) {
256 char *language = NULL;
261 while (!IsEmptyStr(AvailLang[nLocales]))
264 language = getenv("WEBCIT_LANG");
265 if ((language) && (!IsEmptyStr(language)) && (strcmp(language, "UNLIMITED") != 0)) {
266 lprintf(9, "Nailing locale to %s\n", language);
268 else language = NULL;
270 AvailLangLoaded = malloc (sizeof(char*) * nLocales);
271 memset(AvailLangLoaded, 0, sizeof(char*) * nLocales);
272 #ifdef HAVE_USELOCALE
273 wc_locales = malloc (sizeof(locale_t) * nLocales);
274 memset(wc_locales,0, sizeof(locale_t) * nLocales);
275 /* create default locale */
276 Empty_Locale = newlocale(LC_ALL_MASK, NULL, NULL);
282 for (i = 0; i < nLocales; ++i) {
283 if ((language != NULL) && (strcmp(AvailLang[i], language) != 0))
286 sprintf(buf, "%s", AvailLang[i]); /* locale 0 (C) is ascii, not utf-8 */
289 sprintf(buf, "%s.UTF8", AvailLang[i]);
291 #ifdef HAVE_USELOCALE
292 wc_locales[nLocalesLoaded] = newlocale(
293 (LC_MESSAGES_MASK|LC_TIME_MASK),
295 (((i > 0) && (wc_locales[0] != NULL)) ? wc_locales[0] : Empty_Locale)
297 if (wc_locales[nLocalesLoaded] == NULL) {
298 lprintf(1, "locale for "LOCALEDIR"locale/%s: %s; disabled\n",
304 lprintf(3, "Found locale: %s\n", buf);
305 AvailLangLoaded[nLocalesLoaded] = AvailLang[i];
309 if ((language != NULL) && (strcmp(language, AvailLang[i]) == 0)) {
310 setenv("LANG", buf, 1);
311 AvailLangLoaded[nLocalesLoaded] = AvailLang[i];
312 setlocale(LC_MESSAGES, AvailLang[i]);
315 else if (nLocalesLoaded == 0) {
316 setenv("LANG", buf, 1);
317 AvailLangLoaded[nLocalesLoaded] = AvailLang[i];
322 if ((language != NULL) && (nLocalesLoaded == 0)) {
323 lprintf(1, "Your selected locale [%s] isn't available on your system. falling back to C\n", language);
324 #ifdef HAVE_USELOCALE
325 wc_locales[0] = newlocale(
326 (LC_MESSAGES_MASK|LC_TIME_MASK),
330 setlocale(LC_MESSAGES, AvailLang[0]);
331 setenv("LANG", AvailLang[0], 1);
333 AvailLangLoaded[0] = AvailLang[0];
336 #ifndef HAVE_USELOCALE
342 locale = setlocale(LC_ALL, "");
344 lprintf(9, "Message catalog directory: %s\n", bindtextdomain("webcit", LOCALEDIR"/locale"));
345 lprintf(9, "Text domain: %s\n", textdomain("webcit"));
346 lprintf(9, "Text domain Charset: %s\n", bind_textdomain_codeset("webcit","UTF8"));
353 ServerShutdownModule_GETTEXT
356 #ifdef HAVE_USELOCALE
358 for (i = 0; i < nLocalesLoaded; ++i) {
359 if (Empty_Locale != wc_locales[i])
360 freelocale(wc_locales[i]);
364 free(AvailLangLoaded);
367 #else /* ENABLE_NLS */
368 const char *AvailLang[] = {
371 /** \brief dummy for non NLS enabled systems */
372 void tmplput_offer_languages(StrBuf *Target, WCTemplputParams *TP)
374 wprintf("English (US)");
377 /** \brief dummy for non NLS enabled systems */
378 void set_selected_language(char *lang) {
381 /** \brief dummy for non NLS enabled systems */
382 void go_selected_language(void) {
385 /** \brief dummy for non NLS enabled systems */
386 void stop_selected_language(void) {
389 #endif /* ENABLE_NLS */
392 void TmplGettext(StrBuf *Target, WCTemplputParams *TP)
394 StrBufAppendBufPlain(Target, _(TP->Tokens->Params[0]->Start), -1, 0);
399 * Returns the language currently in use.
400 * This function returns a static string, so don't do anything stupid please.
402 const char *get_selected_language(void) {
404 #ifdef HAVE_USELOCALE
405 return AvailLang[WC->selected_language];
418 initialize_locales();
419 RegisterNamespace("LANG:SELECT", 0, 0, tmplput_offer_languages, CTX_NONE);
424 SessionNewModule_GETTEXT
428 OneHttpHeader *vLine = NULL;
430 if ( (sess->Hdr->HTTPHeaders != NULL)
431 && GetHash(sess->Hdr->HTTPHeaders, HKEY("ACCEPT-LANGUAGE"), (void *)&vLine)
433 && (vLine->Val != NULL)
435 StrBuf *accept_language = vLine->Val;
436 httplang_to_locale(accept_language, sess);
442 SessionAttachModule_GETTEXT
446 go_selected_language(); /* set locale */
451 SessionDestroyModule_GETTEXT
455 stop_selected_language(); /* unset locale */