1 /* Some ELinks' auxiliary routines (ELinks<->gettext support) */
2 
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
6 
7 #include <stdlib.h>
8 #include <string.h>
9 
10 #include "elinks.h"
11 
12 #include "intl/gettext/libintl.h"
13 #include "intl/gettext/gettextP.h"
14 #include "util/error.h"
15 #include "util/memory.h"
16 #include "util/string.h"
17 
18 
19 /* See libintl.h for comments.  */
20 int current_charset = -1;
21 
22 /* This is a language lookup table. Indexed by code. */
23 /* Update this everytime you add a new translation. */
24 /* TODO: Try to autogenerate it somehow. Maybe just a complete table? Then we
25  * will anyway need a table of real translations. */
26 struct language languages[] = {
27 	{N_("System"), "system"},
28 	{N_("English"), "en"},
29 
30 	{N_("Belarusian"), "be"},
31 	{N_("Brazilian Portuguese"), "pt-BR"},
32 	{N_("Bulgarian"), "bg"},
33 	{N_("Catalan"), "ca"},
34 	{N_("Croatian"), "hr"},
35 	{N_("Czech"), "cs"},
36 	{N_("Danish"), "da"},
37 	{N_("Dutch"), "nl"},
38 	{N_("Estonian"), "et"},
39 	{N_("Finnish"), "fi"},
40 	{N_("French"), "fr"},
41 	{N_("Galician"), "gl"},
42 	{N_("German"), "de"},
43 	{N_("Greek"), "el"},
44 	{N_("Hungarian"), "hu"},
45 	{N_("Icelandic"), "is"},
46 	{N_("Indonesian"), "id"},
47 	{N_("Italian"), "it"},
48 	{N_("Lithuanian"), "lt"},
49 	{N_("Norwegian"), "no"},
50 	{N_("Polish"), "pl"},
51 	{N_("Portuguese"), "pt"},
52 	{N_("Romanian"), "ro"},
53 	{N_("Russian"), "ru"},
54 	{N_("Serbian"), "sr"},
55 	{N_("Slovak"), "sk"},
56 	{N_("Spanish"), "es"},
57 	{N_("Swedish"), "sv"},
58 	{N_("Turkish"), "tr"},
59 	{N_("Ukrainian"), "uk"},
60 
61 	{NULL, NULL},
62 };
63 
64 /* XXX: In fact this is _NOT_ a real ISO639 code but RFC3066 code (as we're
65  * supposed to use that one when sending language tags through HTTP/1.1) and
66  * that one consists basically from ISO639[-ISO3166].  This is important for
67  * ie. pt vs pt-BR. */
68 /* TODO: We should reflect this in name of this function and of the tag. On the
69  * other side, it's ISO639 for gettext as well etc. So what?  --pasky */
70 
71 int
iso639_to_language(unsigned char * iso639)72 iso639_to_language(unsigned char *iso639)
73 {
74 	unsigned char *l = stracpy(iso639);
75 	unsigned char *p;
76 	int i, ll;
77 
78 	if (!l)
79 		return 1;
80 
81 	/* The environment variable transformation. */
82 
83 	p = strchr(l, '.');
84 	if (p)
85 		*p = '\0';
86 
87 	p = strchr(l, '_');
88 	if (p)
89 		*p = '-';
90 	else
91 		p = strchr(l, '-');
92 
93 	/* Exact match. */
94 
95 	for (i = 0; languages[i].name; i++) {
96 		if (strcmp(languages[i].iso639, l))
97 			continue;
98 		mem_free(l);
99 		return i;
100 	}
101 
102 	/* Base language match. */
103 
104 	if (p) {
105 		*p = '\0';
106 		for (i = 0; languages[i].name; i++) {
107 			if (strcmp(languages[i].iso639, l))
108 				continue;
109 			mem_free(l);
110 			return i;
111 		}
112 	}
113 
114 	/* Any dialect match. */
115 
116 	ll = strlen(l);
117 	for (i = 0; languages[i].name; i++) {
118 		int il = strcspn(languages[i].iso639, "-");
119 
120 		if (strncmp(languages[i].iso639, l, il > ll ? ll : il))
121 			continue;
122 		mem_free(l);
123 		return i;
124 	}
125 
126 	/* Default to english. */
127 
128 	mem_free(l);
129 	return 1;
130 }
131 
132 int system_language = 0;
133 
134 unsigned char *
language_to_iso639(int language)135 language_to_iso639(int language)
136 {
137 	/* Language is "system", we need to extract the index from
138 	 * the environment */
139 	if (language == 0) {
140 		return system_language ?
141 			languages[system_language].iso639 :
142 			languages[get_system_language_index()].iso639;
143 	}
144 
145 	return languages[language].iso639;
146 }
147 
148 int
name_to_language(const unsigned char * name)149 name_to_language(const unsigned char *name)
150 {
151 	int i;
152 
153 	for (i = 0; languages[i].name; i++) {
154 		if (c_strcasecmp(languages[i].name, name))
155 			continue;
156 		return i;
157 	}
158 	return 1;
159 }
160 
161 unsigned char *
language_to_name(int language)162 language_to_name(int language)
163 {
164 	return languages[language].name;
165 }
166 
167 int
get_system_language_index(void)168 get_system_language_index(void)
169 {
170 	unsigned char *l;
171 
172 	/* At this point current_language must be "system" yet. */
173 	l = getenv("LANGUAGE");
174 	if (!l)
175 		l = getenv("LC_ALL");
176 	if (!l)
177 		l = getenv("LC_MESSAGES");
178 	if (!l)
179 		l = getenv("LANG");
180 
181 	return (l) ? iso639_to_language(l) : 1;
182 }
183 
184 int current_language = 0;
185 
186 void
set_language(int language)187 set_language(int language)
188 {
189 	unsigned char *p;
190 
191 	if (!system_language)
192 		system_language = get_system_language_index();
193 
194 	if (language == current_language) {
195 		/* Nothing to do. */
196 		return;
197 	}
198 
199 	current_language = language;
200 
201 	if (!language)
202 		language = system_language;
203 
204 	if (!LANGUAGE) {
205 		/* We never free() this, purely intentionally. */
206 		LANGUAGE = malloc(256);
207 	}
208 	strcpy(LANGUAGE, language_to_iso639(language));
209 	p = strchr(LANGUAGE, '-');
210 	if (p)
211 		*p = '_';
212 
213 	/* Propagate the change to gettext. From the info manual. */
214 	{
215 		extern int _nl_msg_cat_cntr;
216 
217 		_nl_msg_cat_cntr++;
218 	}
219 }
220