2 * Copyright (C) 2010 Robert Ancell.
3 * Author: Robert Ancell <robert.ancell@canonical.com>
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 2 or version 3 of the License.
8 * See http://www.gnu.org/copyleft/lgpl.html the full text of the license.
15 #include <glib/gi18n.h>
17 #include "lightdm/language.h"
31 } LightDMLanguagePrivate;
33 G_DEFINE_TYPE (LightDMLanguage, lightdm_language, G_TYPE_OBJECT);
35 #define GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_LANGUAGE, LightDMLanguagePrivate)
37 static gboolean have_languages = FALSE;
38 static GList *languages = NULL;
41 update_languages (void)
43 gchar *command = "/usr/share/language-tools/language-options";
44 gchar *stdout_text = NULL, *stderr_text = NULL;
52 result = g_spawn_command_line_sync (command, &stdout_text, &stderr_text, &exit_status, &error);
55 g_warning ("Failed to run '%s': %s", command, error->message);
56 g_clear_error (&error);
58 else if (exit_status != 0)
59 g_warning ("Failed to get languages, '%s' returned %d", command, exit_status);
65 tokens = g_strsplit_set (stdout_text, "\n\r", -1);
66 for (i = 0; tokens[i]; i++)
68 LightDMLanguage *language;
71 code = g_strchug (tokens[i]);
75 /* Ignore the non-interesting languages */
76 if (strcmp (command, "locale -a") == 0 && !g_strrstr (code, ".utf8"))
79 language = g_object_new (LIGHTDM_TYPE_LANGUAGE, "code", code, NULL);
80 languages = g_list_append (languages, language);
89 have_languages = TRUE;
93 is_utf8 (const gchar *code)
95 return g_strrstr (code, ".utf8") || g_strrstr (code, ".UTF-8");
98 /* Get a valid locale name that can be passed to setlocale(), so we always can use nl_langinfo() to get language and country names. */
100 get_locale_name (const gchar *code)
102 gchar *locale = NULL, *language;
104 static gchar **avail_locales;
108 return (gchar *) code;
110 if ((at = strchr (code, '@')))
111 language = g_strndup (code, at - code);
113 language = g_strdup (code);
118 GError *error = NULL;
120 if (g_spawn_command_line_sync ("locale -a", &locales, NULL, NULL, &error))
122 avail_locales = g_strsplit (g_strchomp (locales), "\n", -1);
127 g_warning ("Failed to run 'locale -a': %s", error->message);
128 g_clear_error (&error);
134 for (i = 0; avail_locales[i]; i++)
136 gchar *loc = avail_locales[i];
137 if (!g_strrstr (loc, ".utf8"))
139 if (g_str_has_prefix (loc, language))
141 locale = g_strdup (loc);
153 * lightdm_get_language:
155 * Get the current language.
157 * Return value: (transfer none): The current language or #NULL if no language.
160 lightdm_get_language (void)
164 static const gchar *short_lang = NULL;
169 lang = g_getenv ("LANG");
173 /* Convert to a short form language code */
174 gchar *command = g_strconcat ("/usr/share/language-tools/language-validate ", lang, NULL);
176 GError *error = NULL;
177 if (g_spawn_command_line_sync (command, &out, NULL, NULL, &error))
179 short_lang = g_strdup (g_strchomp (out));
185 g_warning ("Failed to run '%s': %s", command, error->message);
186 g_error_free (error);
193 for (link = lightdm_get_languages (); link; link = link->next)
195 LightDMLanguage *language = link->data;
196 if (lightdm_language_matches (language, short_lang))
204 * lightdm_get_languages:
206 * Get a list of languages to present to the user.
208 * Return value: (element-type LightDMLanguage) (transfer none): A list of #LightDMLanguage that should be presented to the user.
211 lightdm_get_languages (void)
218 * lightdm_language_get_code:
219 * @language: A #LightDMLanguage
221 * Get the code of a language (e.g. "de_DE.UTF-8")
223 * Return value: The code of the language
226 lightdm_language_get_code (LightDMLanguage *language)
228 g_return_val_if_fail (LIGHTDM_IS_LANGUAGE (language), NULL);
229 return GET_PRIVATE (language)->code;
233 * lightdm_language_get_name:
234 * @language: A #LightDMLanguage
236 * Get the name of a language.
238 * Return value: The name of the language
241 lightdm_language_get_name (LightDMLanguage *language)
243 LightDMLanguagePrivate *priv;
245 g_return_val_if_fail (LIGHTDM_IS_LANGUAGE (language), NULL);
247 priv = GET_PRIVATE (language);
251 gchar *locale = get_locale_name (priv->code);
254 gchar *current = setlocale (LC_ALL, NULL);
255 setlocale (LC_IDENTIFICATION, locale);
256 setlocale (LC_MESSAGES, "");
258 gchar *language_en = nl_langinfo (_NL_IDENTIFICATION_LANGUAGE);
259 if (language_en && strlen (language_en) > 0)
260 priv->name = g_strdup (dgettext ("iso_639_3", language_en));
262 setlocale (LC_ALL, current);
266 gchar **tokens = g_strsplit_set (priv->code, "_.@", 2);
267 priv->name = g_strdup (tokens[0]);
276 * lightdm_language_get_territory:
277 * @language: A #LightDMLanguage
279 * Get the territory the language is used in.
281 * Return value: The territory the language is used in.
284 lightdm_language_get_territory (LightDMLanguage *language)
286 LightDMLanguagePrivate *priv;
288 g_return_val_if_fail (LIGHTDM_IS_LANGUAGE (language), NULL);
290 priv = GET_PRIVATE (language);
292 if (!priv->territory && strchr (priv->code, '_'))
294 gchar *locale = get_locale_name (priv->code);
297 gchar *current = setlocale (LC_ALL, NULL);
298 setlocale (LC_IDENTIFICATION, locale);
299 setlocale (LC_MESSAGES, "");
301 gchar *country_en = nl_langinfo (_NL_IDENTIFICATION_TERRITORY);
302 if (country_en && strlen (country_en) > 0 && g_strcmp0 (country_en, "ISO") != 0)
303 priv->territory = g_strdup (dgettext ("iso_3166", country_en));
305 setlocale (LC_ALL, current);
307 if (!priv->territory)
309 gchar **tokens = g_strsplit_set (priv->code, "_.@", 3);
310 priv->territory = g_strdup (tokens[1]);
315 return priv->territory;
319 * lightdm_language_matches:
320 * @language: A #LightDMLanguage
321 * @code: A language code
323 * Check if a language code matches this language.
325 * Return value: #TRUE if the code matches this language.
328 lightdm_language_matches (LightDMLanguage *language, const gchar *code)
330 LightDMLanguagePrivate *priv;
332 g_return_val_if_fail (LIGHTDM_IS_LANGUAGE (language), FALSE);
333 g_return_val_if_fail (code != NULL, FALSE);
335 priv = GET_PRIVATE (language);
337 /* Handle the fact the UTF-8 is specified both as '.utf8' and '.UTF-8' */
338 if (is_utf8 (priv->code) && is_utf8 (code))
340 /* Match the characters before the '.' */
342 for (i = 0; priv->code[i] && code[i] && priv->code[i] == code[i] && code[i] != '.' ; i++);
343 return priv->code[i] == '.' && code[i] == '.';
346 return g_str_equal (priv->code, code);
350 lightdm_language_init (LightDMLanguage *language)
355 lightdm_language_set_property (GObject *object,
360 LightDMLanguage *self = LIGHTDM_LANGUAGE (object);
361 LightDMLanguagePrivate *priv = GET_PRIVATE (self);
366 priv->code = g_strdup (g_value_get_string (value));
369 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
375 lightdm_language_get_property (GObject *object,
380 LightDMLanguage *self;
382 self = LIGHTDM_LANGUAGE (object);
386 g_value_set_string (value, lightdm_language_get_code (self));
389 g_value_set_string (value, lightdm_language_get_name (self));
392 g_value_set_string (value, lightdm_language_get_territory (self));
395 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
401 lightdm_language_class_init (LightDMLanguageClass *klass)
403 GObjectClass *object_class = G_OBJECT_CLASS (klass);
405 g_type_class_add_private (klass, sizeof (LightDMLanguagePrivate));
407 object_class->set_property = lightdm_language_set_property;
408 object_class->get_property = lightdm_language_get_property;
410 g_object_class_install_property (object_class,
412 g_param_spec_string ("code",
416 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
417 g_object_class_install_property (object_class,
419 g_param_spec_string ("name",
421 "Name of the language",
424 g_object_class_install_property (object_class,
426 g_param_spec_string ("territory",
428 "Territory the language is from",