10 /* taken from gnome-libs/libgnome/gnome-i18n.c ... */
11 /* FIXME: is this still necessary, or has gtk2.0 swallowed this ? */
13 static GHashTable
*alias_table
= NULL
;
15 /*read an alias file for the locales*/
17 read_aliases (char *file
)
23 alias_table
= g_hash_table_new (g_str_hash
, g_str_equal
);
24 fp
= fopen (file
,"r");
27 while (fgets (buf
,256,fp
)) {
30 if(buf
[0]=='#' || buf
[0]=='\0')
32 p
= strtok(buf
,"\t ");
34 p
= strtok(NULL
,"\t ");
36 g_hash_table_insert (alias_table
, g_strdup(buf
), g_strdup(p
));
42 free_alias_cb(gpointer key
, gpointer value
, gpointer user_data
)
49 free_alias_table(void)
53 g_hash_table_foreach(alias_table
, free_alias_cb
, NULL
);
54 g_hash_table_destroy(alias_table
);
58 /*return the un-aliased language as a newly allocated string*/
60 unalias_lang (char *lang
)
65 read_aliases ("/usr/share/locale/locale.alias");
66 read_aliases ("/usr/local/share/locale/locale.alias");
67 read_aliases ("/usr/lib/X11/locale/locale.alias");
68 read_aliases ("/usr/openwin/lib/locale/locale.alias");
70 while((p
=g_hash_table_lookup(alias_table
,lang
)) && strcmp(p
, lang
))
75 /* Mask for components of locale spec. The ordering here is from
76 * least significant to most significant
80 COMPONENT_CODESET
= 1 << 0,
81 COMPONENT_TERRITORY
= 1 << 1,
82 COMPONENT_MODIFIER
= 1 << 2
85 /* Break an X/Open style locale specification into components
88 explode_locale (const gchar
*locale
,
94 const gchar
*uscore_pos
;
100 uscore_pos
= strchr (locale
, '_');
101 dot_pos
= strchr (uscore_pos
? uscore_pos
: locale
, '.');
102 at_pos
= strchr (dot_pos
? dot_pos
: (uscore_pos
? uscore_pos
: locale
), '@');
105 mask
|= COMPONENT_MODIFIER
;
106 *modifier
= g_strdup (at_pos
);
108 at_pos
= locale
+ strlen (locale
);
111 mask
|= COMPONENT_CODESET
;
112 *codeset
= g_new (gchar
, 1 + at_pos
- dot_pos
);
113 strncpy (*codeset
, dot_pos
, at_pos
- dot_pos
);
114 (*codeset
)[at_pos
- dot_pos
] = '\0';
119 mask
|= COMPONENT_TERRITORY
;
120 *territory
= g_new (gchar
, 1 + dot_pos
- uscore_pos
);
121 strncpy (*territory
, uscore_pos
, dot_pos
- uscore_pos
);
122 (*territory
)[dot_pos
- uscore_pos
] = '\0';
124 uscore_pos
= dot_pos
;
126 *language
= g_new (gchar
, 1 + uscore_pos
- locale
);
127 strncpy (*language
, locale
, uscore_pos
- locale
);
128 (*language
)[uscore_pos
- locale
] = '\0';
134 * Compute all interesting variants for a given locale name -
135 * by stripping off different components of the value.
137 * For simplicity, we assume that the locale is in
138 * X/Open format: language[_territory][.codeset][@modifier]
140 * TODO: Extend this to handle the CEN format (see the GNUlibc docs)
141 * as well. We could just copy the code from glibc wholesale
142 * but it is big, ugly, and complicated, so I'm reluctant
143 * to do so when this should handle 99% of the time...
146 compute_locale_variants (const gchar
*locale
)
148 GList
*retval
= NULL
;
158 g_return_val_if_fail (locale
!= NULL
, NULL
);
160 mask
= explode_locale (locale
, &language
, &territory
, &codeset
, &modifier
);
162 /* Iterate through all possible combinations, from least attractive
163 * to most attractive.
165 for (i
=0; i
<=mask
; i
++)
166 if ((i
& ~mask
) == 0)
168 gchar
*val
= g_strconcat(language
,
169 (i
& COMPONENT_TERRITORY
) ? territory
: "",
170 (i
& COMPONENT_CODESET
) ? codeset
: "",
171 (i
& COMPONENT_MODIFIER
) ? modifier
: "",
173 retval
= g_list_prepend (retval
, val
);
177 if (mask
& COMPONENT_CODESET
)
179 if (mask
& COMPONENT_TERRITORY
)
181 if (mask
& COMPONENT_MODIFIER
)
187 /* The following is (partly) taken from the gettext package.
188 Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc. */
191 guess_category_value (const gchar
*categoryname
)
195 /* The highest priority value is the `LANGUAGE' environment
196 variable. This is a GNU extension. */
197 retval
= getenv ("LANGUAGE");
198 if (retval
!= NULL
&& retval
[0] != '\0')
201 /* `LANGUAGE' is not set. So we have to proceed with the POSIX
202 methods of looking to `LC_ALL', `LC_xxx', and `LANG'. On some
203 systems this can be done by the `setlocale' function itself. */
205 /* Setting of LC_ALL overwrites all other. */
206 retval
= getenv ("LC_ALL");
207 if (retval
!= NULL
&& retval
[0] != '\0')
210 /* Next comes the name of the desired category. */
211 retval
= getenv (categoryname
);
212 if (retval
!= NULL
&& retval
[0] != '\0')
215 /* Last possibility is the LANG environment variable. */
216 retval
= getenv ("LANG");
217 if (retval
!= NULL
&& retval
[0] != '\0')
224 get_language_list(const gchar
*category_name
)
227 gint c_locale_defined
= FALSE
;
229 const gchar
*category_value
;
230 gchar
*category_memory
, *orig_category_memory
;
233 category_name
= "LC_ALL";
235 category_value
= guess_category_value (category_name
);
236 if (! category_value
)
237 category_value
= "C";
238 orig_category_memory
= category_memory
=
239 g_malloc (strlen (category_value
)+1);
241 while (category_value
[0] != '\0') {
242 while (category_value
[0] != '\0' && category_value
[0] == ':')
245 if (category_value
[0] != '\0') {
246 char *cp
= category_memory
;
248 while (category_value
[0] != '\0' && category_value
[0] != ':')
249 *category_memory
++= *category_value
++;
251 category_memory
[0]= '\0';
254 cp
= unalias_lang(cp
);
256 if (strcmp (cp
, "C") == 0)
257 c_locale_defined
= TRUE
;
259 list
= g_list_concat (list
, compute_locale_variants (cp
));
263 g_free (orig_category_memory
);
265 if (!c_locale_defined
)
266 list
= g_list_append (list
, "C");
274 intl_get_language_list(void)
276 static const GList
*list
= NULL
;
280 list
= gnome_i18n_get_language_list("LC_MESSAGES");
282 list
= get_language_list("LC_MESSAGES");
289 /* low numbers are better */
291 intl_score_locale(const gchar
*locale
)
293 const GList
*list
= intl_get_language_list();
297 /* NULL is same as C locale */
299 return g_list_length((GList
*)list
) - 1;
300 for (tmp
= list
, i
= 0; tmp
; tmp
= tmp
->next
, i
++)
301 if (!strcmp((const char *)tmp
->data
, locale
))
303 if (!tmp
) /* not found */