#ifdef'd xmlerror.h
[dia.git] / lib / intl.c
blobcb6805b5fe853f7fa36f4a9c618ccd05c5f6218c
1 #include <config.h>
3 #include "intl.h"
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
9 #ifndef GNOME
10 /* taken from gnome-libs/libgnome/gnome-i18n.c ... */
12 static GHashTable *alias_table = NULL;
14 /*read an alias file for the locales*/
15 static void
16 read_aliases (char *file)
18 FILE *fp;
19 char buf[256];
21 if (!alias_table)
22 alias_table = g_hash_table_new (g_str_hash, g_str_equal);
23 fp = fopen (file,"r");
24 if (!fp)
25 return;
26 while (fgets (buf,256,fp)) {
27 char *p;
28 g_strstrip(buf);
29 if(buf[0]=='#' || buf[0]=='\0')
30 continue;
31 p = strtok(buf,"\t ");
32 if(!p) continue;
33 p = strtok(NULL,"\t ");
34 if(!p) continue;
35 g_hash_table_insert (alias_table, g_strdup(buf), g_strdup(p));
37 fclose (fp);
40 static void
41 free_alias_cb(gpointer key, gpointer value, gpointer user_data)
43 g_free(key);
44 g_free(value);
47 static void
48 free_alias_table(void)
50 if (!alias_table)
51 return;
52 g_hash_table_foreach(alias_table, free_alias_cb, NULL);
53 g_hash_table_destroy(alias_table);
54 alias_table = NULL;
57 /*return the un-aliased language as a newly allocated string*/
58 static char *
59 unalias_lang (char *lang)
61 char *p;
63 if(!alias_table) {
64 read_aliases ("/usr/share/locale/locale.alias");
65 read_aliases ("/usr/local/share/locale/locale.alias");
66 read_aliases ("/usr/lib/X11/locale/locale.alias");
67 read_aliases ("/usr/openwin/lib/locale/locale.alias");
69 while((p=g_hash_table_lookup(alias_table,lang)) && strcmp(p, lang))
70 lang = p;
71 return lang;
74 /* Mask for components of locale spec. The ordering here is from
75 * least significant to most significant
77 enum
79 COMPONENT_CODESET = 1 << 0,
80 COMPONENT_TERRITORY = 1 << 1,
81 COMPONENT_MODIFIER = 1 << 2
84 /* Break an X/Open style locale specification into components
86 static guint
87 explode_locale (const gchar *locale,
88 gchar **language,
89 gchar **territory,
90 gchar **codeset,
91 gchar **modifier)
93 const gchar *uscore_pos;
94 const gchar *at_pos;
95 const gchar *dot_pos;
97 guint mask = 0;
99 uscore_pos = strchr (locale, '_');
100 dot_pos = strchr (uscore_pos ? uscore_pos : locale, '.');
101 at_pos = strchr (dot_pos ? dot_pos : (uscore_pos ? uscore_pos : locale), '@');
103 if (at_pos) {
104 mask |= COMPONENT_MODIFIER;
105 *modifier = g_strdup (at_pos);
106 } else
107 at_pos = locale + strlen (locale);
109 if (dot_pos) {
110 mask |= COMPONENT_CODESET;
111 *codeset = g_new (gchar, 1 + at_pos - dot_pos);
112 strncpy (*codeset, dot_pos, at_pos - dot_pos);
113 (*codeset)[at_pos - dot_pos] = '\0';
114 } else
115 dot_pos = at_pos;
117 if (uscore_pos) {
118 mask |= COMPONENT_TERRITORY;
119 *territory = g_new (gchar, 1 + dot_pos - uscore_pos);
120 strncpy (*territory, uscore_pos, dot_pos - uscore_pos);
121 (*territory)[dot_pos - uscore_pos] = '\0';
122 } else
123 uscore_pos = dot_pos;
125 *language = g_new (gchar, 1 + uscore_pos - locale);
126 strncpy (*language, locale, uscore_pos - locale);
127 (*language)[uscore_pos - locale] = '\0';
129 return mask;
133 * Compute all interesting variants for a given locale name -
134 * by stripping off different components of the value.
136 * For simplicity, we assume that the locale is in
137 * X/Open format: language[_territory][.codeset][@modifier]
139 * TODO: Extend this to handle the CEN format (see the GNUlibc docs)
140 * as well. We could just copy the code from glibc wholesale
141 * but it is big, ugly, and complicated, so I'm reluctant
142 * to do so when this should handle 99% of the time...
144 static GList *
145 compute_locale_variants (const gchar *locale)
147 GList *retval = NULL;
149 gchar *language;
150 gchar *territory;
151 gchar *codeset;
152 gchar *modifier;
154 guint mask;
155 guint i;
157 g_return_val_if_fail (locale != NULL, NULL);
159 mask = explode_locale (locale, &language, &territory, &codeset, &modifier);
161 /* Iterate through all possible combinations, from least attractive
162 * to most attractive.
164 for (i=0; i<=mask; i++)
165 if ((i & ~mask) == 0)
167 gchar *val = g_strconcat(language,
168 (i & COMPONENT_TERRITORY) ? territory : "",
169 (i & COMPONENT_CODESET) ? codeset : "",
170 (i & COMPONENT_MODIFIER) ? modifier : "",
171 NULL);
172 retval = g_list_prepend (retval, val);
175 g_free (language);
176 if (mask & COMPONENT_CODESET)
177 g_free (codeset);
178 if (mask & COMPONENT_TERRITORY)
179 g_free (territory);
180 if (mask & COMPONENT_MODIFIER)
181 g_free (modifier);
183 return retval;
186 /* The following is (partly) taken from the gettext package.
187 Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc. */
189 static const gchar *
190 guess_category_value (const gchar *categoryname)
192 const gchar *retval;
194 /* The highest priority value is the `LANGUAGE' environment
195 variable. This is a GNU extension. */
196 retval = getenv ("LANGUAGE");
197 if (retval != NULL && retval[0] != '\0')
198 return retval;
200 /* `LANGUAGE' is not set. So we have to proceed with the POSIX
201 methods of looking to `LC_ALL', `LC_xxx', and `LANG'. On some
202 systems this can be done by the `setlocale' function itself. */
204 /* Setting of LC_ALL overwrites all other. */
205 retval = getenv ("LC_ALL");
206 if (retval != NULL && retval[0] != '\0')
207 return retval;
209 /* Next comes the name of the desired category. */
210 retval = getenv (categoryname);
211 if (retval != NULL && retval[0] != '\0')
212 return retval;
214 /* Last possibility is the LANG environment variable. */
215 retval = getenv ("LANG");
216 if (retval != NULL && retval[0] != '\0')
217 return retval;
219 return NULL;
222 static GList *
223 get_language_list(const gchar *category_name)
225 GList *list = NULL;
226 gint c_locale_defined= FALSE;
228 const gchar *category_value;
229 gchar *category_memory, *orig_category_memory;
231 if (!category_name)
232 category_name= "LC_ALL";
234 category_value = guess_category_value (category_name);
235 if (! category_value)
236 category_value = "C";
237 orig_category_memory = category_memory =
238 g_malloc (strlen (category_value)+1);
240 while (category_value[0] != '\0') {
241 while (category_value[0] != '\0' && category_value[0] == ':')
242 ++category_value;
244 if (category_value[0] != '\0') {
245 char *cp= category_memory;
247 while (category_value[0] != '\0' && category_value[0] != ':')
248 *category_memory++= *category_value++;
250 category_memory[0]= '\0';
251 category_memory++;
253 cp = unalias_lang(cp);
255 if (strcmp (cp, "C") == 0)
256 c_locale_defined= TRUE;
258 list= g_list_concat (list, compute_locale_variants (cp));
262 g_free (orig_category_memory);
264 if (!c_locale_defined)
265 list= g_list_append (list, "C");
267 return list;
270 #endif
272 GList *
273 intl_get_language_list(void)
275 static GList *list = NULL;
277 if (!list) {
278 #ifdef GNOME
279 list = gnome_i18n_get_language_list("LC_MESSAGES");
280 #else
281 list = get_language_list("LC_MESSAGES");
282 free_alias_table();
283 #endif
285 return list;
288 /* low numbers are better */
290 intl_score_locale(const gchar *locale)
292 GList *list = intl_get_language_list();
293 GList *tmp;
294 int i;
296 /* NULL is same as C locale */
297 if (!locale)
298 return g_list_length(list) - 1;
299 for (tmp = list, i = 0; tmp; tmp = tmp->next, i++)
300 if (!strcmp((char *)tmp->data, locale))
301 break;
302 if (!tmp) /* not found */
303 i = G_MAXINT;
304 return i;