2 * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
5 * This file is part of the Gnome Library.
7 * The Gnome Library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
12 * The Gnome Library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with the Gnome Library; see the file COPYING.LIB. If not,
19 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
24 #include "gnome-vfs-i18n.h"
26 #include "gnome-vfs-private-utils.h"
29 #include <glib/ghash.h>
30 #include <glib/gmessages.h>
31 #include <glib/gstrfuncs.h>
32 #include <glib/gutils.h>
38 #include <sys/types.h>
43 static GHashTable *alias_table = NULL;
44 static GHashTable *category_table = NULL;
46 /*read an alias file for the locales*/
48 read_aliases (char *file)
54 alias_table = g_hash_table_new (g_str_hash, g_str_equal);
55 fp = fopen (file,"r");
58 while (fgets (buf, 256, fp))
64 /* Line is a comment */
65 if ((buf[0] == '#') || (buf[0] == '\0'))
68 /* Reads first column */
69 for (p = buf, q = NULL; *p; p++) {
70 if ((*p == '\t') || (*p == ' ') || (*p == ':')) {
73 while ((*q == '\t') || (*q == ' ')) {
79 /* The line only had one column */
83 /* Read second column */
84 for (p = q; *p; p++) {
85 if ((*p == '\t') || (*p == ' ')) {
91 /* Add to alias table if necessary */
92 if (!g_hash_table_lookup (alias_table, buf)) {
93 g_hash_table_insert (alias_table, g_strdup (buf), g_strdup (q));
100 unalias_lang (char *lang)
107 read_aliases ("/usr/share/locale/locale.alias");
108 read_aliases ("/usr/local/share/locale/locale.alias");
109 read_aliases ("/usr/lib/X11/locale/locale.alias");
110 read_aliases ("/usr/openwin/lib/locale/locale.alias");
113 while ((p = g_hash_table_lookup (alias_table, lang)) && (strcmp (p, lang) != 0))
118 static gboolean said_before = FALSE;
120 g_warning ("Too many alias levels for a locale, "
121 "may indicate a loop");
129 /* Mask for components of locale spec. The ordering here is from
130 * least significant to most significant
134 COMPONENT_CODESET = 1 << 0,
135 COMPONENT_TERRITORY = 1 << 1,
136 COMPONENT_MODIFIER = 1 << 2
139 /* Break an X/Open style locale specification into components
142 explode_locale (const gchar *locale,
148 const gchar *uscore_pos;
150 const gchar *dot_pos;
154 uscore_pos = strchr (locale, '_');
155 dot_pos = strchr (uscore_pos ? uscore_pos : locale, '.');
156 at_pos = strchr (dot_pos ? dot_pos : (uscore_pos ? uscore_pos : locale), '@');
160 mask |= COMPONENT_MODIFIER;
161 *modifier = g_strdup (at_pos);
164 at_pos = locale + strlen (locale);
168 mask |= COMPONENT_CODESET;
169 *codeset = g_strndup (dot_pos, at_pos - dot_pos);
176 mask |= COMPONENT_TERRITORY;
177 *territory = g_strndup (uscore_pos, dot_pos - uscore_pos);
180 uscore_pos = dot_pos;
182 *language = g_strndup (locale, uscore_pos - locale);
188 * Compute all interesting variants for a given locale name -
189 * by stripping off different components of the value.
191 * For simplicity, we assume that the locale is in
192 * X/Open format: language[_territory][.codeset][@modifier]
194 * TODO: Extend this to handle the CEN format (see the GNUlibc docs)
195 * as well. We could just copy the code from glibc wholesale
196 * but it is big, ugly, and complicated, so I'm reluctant
197 * to do so when this should handle 99% of the time...
200 compute_locale_variants (const gchar *locale)
202 GList *retval = NULL;
212 g_return_val_if_fail (locale != NULL, NULL);
214 mask = explode_locale (locale, &language, &territory, &codeset, &modifier);
216 /* Iterate through all possible combinations, from least attractive
217 * to most attractive.
219 for (i = 0; i <= mask; i++)
220 if ((i & ~mask) == 0)
222 gchar *val = g_strconcat (language,
223 (i & COMPONENT_TERRITORY) ? territory : "",
224 (i & COMPONENT_CODESET) ? codeset : "",
225 (i & COMPONENT_MODIFIER) ? modifier : "",
227 retval = g_list_prepend (retval, val);
231 if (mask & COMPONENT_CODESET)
233 if (mask & COMPONENT_TERRITORY)
235 if (mask & COMPONENT_MODIFIER)
241 /* The following is (partly) taken from the gettext package.
242 Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc. */
245 guess_category_value (const gchar *categoryname)
249 /* The highest priority value is the `LANGUAGE' environment
250 variable. This is a GNU extension. */
251 retval = g_getenv ("LANGUAGE");
252 if ((retval != NULL) && (retval[0] != '\0'))
255 /* `LANGUAGE' is not set. So we have to proceed with the POSIX
256 methods of looking to `LC_ALL', `LC_xxx', and `LANG'. On some
257 systems this can be done by the `setlocale' function itself. */
259 /* Setting of LC_ALL overwrites all other. */
260 retval = g_getenv ("LC_ALL");
261 if ((retval != NULL) && (retval[0] != '\0'))
264 /* Next comes the name of the desired category. */
265 retval = g_getenv (categoryname);
266 if ((retval != NULL) && (retval[0] != '\0'))
269 /* Last possibility is the LANG environment variable. */
270 retval = g_getenv ("LANG");
271 if ((retval != NULL) && (retval[0] != '\0'))
278 * gnome_vfs_i18n_get_language_list:
279 * @category_name: Name of category to look up, e.g. "LC_MESSAGES".
281 * This computes a list of language strings. It searches in the
282 * standard environment variables to find the list, which is sorted
283 * in order from most desirable to least desirable. The `C' locale
284 * is appended to the list if it does not already appear (other
285 * routines depend on this behaviour).
286 * If @category_name is %NULL, then LC_ALL is assumed.
288 * Return value: a copy of the list of languages (which you need to free).
291 gnome_vfs_i18n_get_language_list (const gchar *category_name)
296 category_name = "LC_ALL";
300 list = g_hash_table_lookup (category_table, (const gpointer) category_name);
304 category_table = g_hash_table_new (g_str_hash, g_str_equal);
310 gint c_locale_defined = FALSE;
312 const gchar *category_value;
313 gchar *category_memory, *orig_category_memory;
315 category_value = guess_category_value (category_name);
317 category_value = "C";
318 orig_category_memory = category_memory =
319 g_malloc (strlen (category_value)+1);
321 while (category_value[0] != '\0')
323 while ((category_value[0] != '\0') && (category_value[0] == ':'))
326 if (category_value[0] != '\0')
328 char *cp = category_memory;
330 while ((category_value[0] != '\0') && (category_value[0] != ':'))
331 *category_memory++ = *category_value++;
333 category_memory[0] = '\0';
336 cp = unalias_lang (cp);
338 if (strcmp (cp, "C") == 0)
339 c_locale_defined = TRUE;
341 list = g_list_concat (list, compute_locale_variants (cp));
345 g_free (orig_category_memory);
347 if (!c_locale_defined)
348 list= g_list_append (list, "C");
350 g_hash_table_insert (category_table, (gpointer) category_name, list);
353 return g_list_copy (list);