]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - liblightdm-gobject/language.c
Set LANG variable based on the user language
[sojka/lightdm.git] / liblightdm-gobject / language.c
1 /*
2  * Copyright (C) 2010 Robert Ancell.
3  * Author: Robert Ancell <robert.ancell@canonical.com>
4  * 
5  * This library is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU Lesser General Public License as published by the Free
7  * Software Foundation; either version 3 of the License, or (at your option) any
8  * later version. See http://www.gnu.org/copyleft/lgpl.html the full text of the
9  * license.
10  */
11
12 #include <string.h>
13 #include <locale.h>
14 #include <langinfo.h>
15
16 #include "lightdm/language.h"
17
18 enum {
19     PROP_0,
20     PROP_CODE,
21     PROP_NAME,
22     PROP_TERRITORY
23 };
24
25 typedef struct
26 {
27     gchar *code;
28     gchar *name;
29     gchar *territory;
30 } LightDMLanguagePrivate;
31
32 G_DEFINE_TYPE (LightDMLanguage, lightdm_language, G_TYPE_OBJECT);
33
34 #define GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_LANGUAGE, LightDMLanguagePrivate)
35
36 static gboolean have_languages = FALSE;
37 static GList *languages = NULL;
38
39 static void
40 update_languages (void)
41 {
42     gchar *stdout_text = NULL, *stderr_text = NULL;
43     gint exit_status;
44     gboolean result;
45     GError *error = NULL;
46
47     if (have_languages)
48         return;
49
50     result = g_spawn_command_line_sync ("locale -a", &stdout_text, &stderr_text, &exit_status, &error);
51     if (error)
52     {
53         g_warning ("Failed to run 'locale -a': %s", error->message);
54         g_clear_error (&error);
55     }
56     else if (exit_status != 0)
57         g_warning ("Failed to get languages, locale -a returned %d", exit_status);
58     else if (result)
59     {
60         gchar **tokens;
61         int i;
62
63         tokens = g_strsplit_set (stdout_text, "\n\r", -1);
64         for (i = 0; tokens[i]; i++)
65         {
66             LightDMLanguage *language;
67             gchar *code;
68
69             code = g_strchug (tokens[i]);
70             if (code[0] == '\0')
71                 continue;
72
73             /* Ignore the non-interesting languages */
74             if (strcmp (code, "C") == 0 || strcmp (code, "POSIX") == 0)
75                 continue;
76
77             language = g_object_new (LIGHTDM_TYPE_LANGUAGE, "code", code, NULL);
78             languages = g_list_append (languages, language);
79         }
80
81         g_strfreev (tokens);
82     }
83
84     g_free (stdout_text);
85     g_free (stderr_text);
86
87     have_languages = TRUE;
88 }
89
90 /**
91  * lightdm_get_language:
92  *
93  * Get the current language.
94  *
95  * Return value: (transfer none): The current language or #NULL if no language.
96  **/
97 const LightDMLanguage *
98 lightdm_get_language (void)
99 {
100     const gchar *lang;
101     GList *link;
102
103     lang = g_getenv ("LANG");
104     for (link = lightdm_get_languages (); link; link = link->next)
105     {
106         LightDMLanguage *language = link->data;
107         if (lightdm_language_matches (language, lang))
108             return language;
109     }
110
111     return NULL;
112 }
113
114 /**
115  * lightdm_get_languages:
116  *
117  * Get a list of languages to present to the user.
118  *
119  * Return value: (element-type LightDMLanguage) (transfer none): A list of #LightDMLanguage that should be presented to the user.
120  **/
121 GList *
122 lightdm_get_languages (void)
123 {
124     update_languages ();
125     return languages;
126 }
127
128 /**
129  * lightdm_language_get_code:
130  * @language: A #LightDMLanguage
131  * 
132  * Get the code of a language.
133  * 
134  * Return value: The code of the language
135  **/
136 const gchar *
137 lightdm_language_get_code (LightDMLanguage *language)
138 {
139     g_return_val_if_fail (LIGHTDM_IS_LANGUAGE (language), NULL);
140     return GET_PRIVATE (language)->code;
141 }
142
143 /**
144  * lightdm_language_get_name:
145  * @language: A #LightDMLanguage
146  * 
147  * Get the name of a language.
148  *
149  * Return value: The name of the language
150  **/
151 const gchar *
152 lightdm_language_get_name (LightDMLanguage *language)
153 {
154     LightDMLanguagePrivate *priv;
155
156     g_return_val_if_fail (LIGHTDM_IS_LANGUAGE (language), NULL);
157
158     priv = GET_PRIVATE (language);
159
160     if (!priv->name)
161     {
162         char *current = setlocale(LC_ALL, NULL);
163         setlocale(LC_ALL, priv->code);
164 #ifdef _NL_IDENTIFICATION_LANGUAGE
165         priv->name = g_strdup (nl_langinfo (_NL_IDENTIFICATION_LANGUAGE));
166 #else
167         priv->name = g_strdup ("Unknown");
168 #endif
169         setlocale(LC_ALL, current);
170     }
171
172     return priv->name;
173 }
174
175 /**
176  * lightdm_language_get_territory:
177  * @language: A #LightDMLanguage
178  * 
179  * Get the territory the language is used in.
180  * 
181  * Return value: The territory the language is used in.
182  **/
183 const gchar *
184 lightdm_language_get_territory (LightDMLanguage *language)
185 {
186     LightDMLanguagePrivate *priv;
187
188     g_return_val_if_fail (LIGHTDM_IS_LANGUAGE (language), NULL);
189
190     priv = GET_PRIVATE (language);
191
192     if (!priv->territory)
193     {
194         char *current = setlocale(LC_ALL, NULL);
195         setlocale(LC_ALL, priv->code);
196 #ifdef _NL_IDENTIFICATION_TERRITORY
197         priv->territory = g_strdup (nl_langinfo (_NL_IDENTIFICATION_TERRITORY));
198 #else
199         priv->territory = g_strdup ("Unknown");
200 #endif
201         setlocale(LC_ALL, current);
202     }
203
204     return priv->territory;
205 }
206
207 static gboolean
208 is_utf8 (const gchar *code)
209 {
210     return g_str_has_suffix (code, ".utf8") || g_str_has_suffix (code, ".UTF-8");
211 }
212
213 /**
214  * lightdm_language_matches:
215  * @language: A #LightDMLanguage
216  * @code: A language code
217  * 
218  * Check if a language code matches this language.
219  * 
220  * Return value: #TRUE if the code matches this language.
221  **/
222 gboolean
223 lightdm_language_matches (LightDMLanguage *language, const gchar *code)
224 {
225     LightDMLanguagePrivate *priv;
226
227     g_return_val_if_fail (LIGHTDM_IS_LANGUAGE (language), FALSE);
228     g_return_val_if_fail (code != NULL, FALSE);
229
230     priv = GET_PRIVATE (language);
231
232     /* Handle the fact the UTF-8 is specified both as '.utf8' and '.UTF-8' */
233     if (is_utf8 (priv->code) && is_utf8 (code))
234     {
235         /* Match the characters before the '.' */
236         int i;
237         for (i = 0; priv->code[i] && code[i] && priv->code[i] == code[i] && code[i] != '.' ; i++);
238         return priv->code[i] == '.' && code[i] == '.';
239     }
240
241     return g_str_equal (priv->code, code);
242 }
243
244 static void
245 lightdm_language_init (LightDMLanguage *language)
246 {
247 }
248
249 static void
250 lightdm_language_set_property (GObject      *object,
251                            guint         prop_id,
252                            const GValue *value,
253                            GParamSpec   *pspec)
254 {
255     LightDMLanguage *self = LIGHTDM_LANGUAGE (object);
256     LightDMLanguagePrivate *priv = GET_PRIVATE (self);
257
258     switch (prop_id) {
259     case PROP_CODE:
260         g_free (priv->name);
261         priv->code = g_strdup (g_value_get_string (value));
262         break;
263     default:
264         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
265         break;
266     }
267 }
268
269 static void
270 lightdm_language_get_property (GObject    *object,
271                            guint       prop_id,
272                            GValue     *value,
273                            GParamSpec *pspec)
274 {
275     LightDMLanguage *self;
276
277     self = LIGHTDM_LANGUAGE (object);
278
279     switch (prop_id) {
280     case PROP_CODE:
281         g_value_set_string (value, lightdm_language_get_code (self));
282         break;
283     case PROP_NAME:
284         g_value_set_string (value, lightdm_language_get_name (self));
285         break;
286     case PROP_TERRITORY:
287         g_value_set_string (value, lightdm_language_get_territory (self));
288         break;
289     default:
290         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
291         break;
292     }
293 }
294
295 static void
296 lightdm_language_class_init (LightDMLanguageClass *klass)
297 {
298     GObjectClass *object_class = G_OBJECT_CLASS (klass);
299   
300     g_type_class_add_private (klass, sizeof (LightDMLanguagePrivate));
301
302     object_class->set_property = lightdm_language_set_property;
303     object_class->get_property = lightdm_language_get_property;
304
305     g_object_class_install_property (object_class,
306                                      PROP_CODE,
307                                      g_param_spec_string ("code",
308                                                           "code",
309                                                           "Language code",
310                                                           NULL,
311                                                           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
312     g_object_class_install_property (object_class,
313                                      PROP_NAME,
314                                      g_param_spec_string ("name",
315                                                           "name",
316                                                           "Name of the language",
317                                                           NULL,
318                                                           G_PARAM_READABLE));
319     g_object_class_install_property (object_class,
320                                      PROP_TERRITORY,
321                                      g_param_spec_string ("territory",
322                                                           "territory",
323                                                           "Territory the language is from",
324                                                           NULL,
325                                                           G_PARAM_READABLE));
326 }