diff --git a/app/app.c b/app/app.c index 0c9bd87a72..64c85b3c13 100644 --- a/app/app.c +++ b/app/app.c @@ -280,8 +280,6 @@ app_init_language (const gchar *language) if (! language) return; - g_printerr ("Setting language to %s\n", language); - g_setenv ("LANGUAGE", language, TRUE); setlocale (LC_ALL, ""); } diff --git a/app/widgets/Makefile.am b/app/widgets/Makefile.am index 1bc7db3dd0..a595be1f24 100644 --- a/app/widgets/Makefile.am +++ b/app/widgets/Makefile.am @@ -314,6 +314,8 @@ libappwidgets_a_sources = \ gimptooloptionseditor.h \ gimptooloverlay.c \ gimptooloverlay.h \ + gimptranslationstore.c \ + gimptranslationstore.h \ gimpuimanager.c \ gimpuimanager.h \ gimpundoeditor.c \ diff --git a/app/widgets/gimplanguagecombobox.c b/app/widgets/gimplanguagecombobox.c index a8a767b550..4411c6bba8 100644 --- a/app/widgets/gimplanguagecombobox.c +++ b/app/widgets/gimplanguagecombobox.c @@ -31,7 +31,7 @@ #include "widgets-types.h" #include "gimplanguagecombobox.h" -#include "gimplanguagestore.h" +#include "gimptranslationstore.h" struct _GimpLanguageComboBox @@ -60,7 +60,7 @@ gimp_language_combo_box_init (GimpLanguageComboBox *combo) gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE); gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer, - "text", GIMP_LANGUAGE_STORE_LANGUAGE, + "text", GIMP_LANGUAGE_STORE_LANGUAGE, NULL); } @@ -70,7 +70,7 @@ gimp_language_combo_box_new (void) GtkWidget *combo; GtkListStore *store; - store = gimp_language_store_new (); + store = gimp_translation_store_new (); combo = g_object_new (GIMP_TYPE_LANGUAGE_COMBO_BOX, "model", store, diff --git a/app/widgets/gimplanguageentry.c b/app/widgets/gimplanguageentry.c index a2967771f7..303f8f5184 100644 --- a/app/widgets/gimplanguageentry.c +++ b/app/widgets/gimplanguageentry.c @@ -165,8 +165,7 @@ gimp_language_entry_set_property (GObject *object, switch (property_id) { case PROP_MODEL: - if (entry->store) - g_object_unref (entry->store); + g_return_if_fail (entry->store == NULL); entry->store = g_value_dup_object (value); break; diff --git a/app/widgets/gimplanguagestore-parser.c b/app/widgets/gimplanguagestore-parser.c index 17969250b9..59c31eaa70 100644 --- a/app/widgets/gimplanguagestore-parser.c +++ b/app/widgets/gimplanguagestore-parser.c @@ -2,7 +2,7 @@ * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * gimplanguagestore-parser.c - * Copyright (C) 2008 Sven Neumann + * Copyright (C) 2008, 2009 Sven Neumann * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -68,28 +68,13 @@ static void iso_codes_parser_start_unknown (IsoCodesParser *parser); static void iso_codes_parser_end_unknown (IsoCodesParser *parser); -static const GMarkupParser markup_parser = +static void +iso_codes_parser_init (void) { - iso_codes_parser_start_element, - iso_codes_parser_end_element, - NULL, /* characters */ - NULL, /* passthrough */ - NULL /* error */ -}; + static gboolean initialized = FALSE; - -gboolean -gimp_language_store_populate (GimpLanguageStore *store, - GError **error) -{ -#ifdef HAVE_ISO_CODES - GimpXmlParser *xml_parser; - gchar *filename; - gboolean success; - IsoCodesParser parser = { 0, }; - - g_return_val_if_fail (GIMP_IS_LANGUAGE_STORE (store), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + if (initialized) + return; #ifdef G_OS_WIN32 /* on Win32, assume iso-codes is installed in the same location as GIMP */ @@ -100,6 +85,33 @@ gimp_language_store_populate (GimpLanguageStore *store, bind_textdomain_codeset ("iso_639", "UTF-8"); + initialized = TRUE; +} + +gboolean +gimp_language_store_parse_iso_codes (GimpLanguageStore *store, + GError **error) +{ +#ifdef HAVE_ISO_CODES + static const GMarkupParser markup_parser = + { + iso_codes_parser_start_element, + iso_codes_parser_end_element, + NULL, /* characters */ + NULL, /* passthrough */ + NULL /* error */ + }; + + GimpXmlParser *xml_parser; + gchar *filename; + gboolean success; + IsoCodesParser parser = { 0, }; + + g_return_val_if_fail (GIMP_IS_LANGUAGE_STORE (store), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + iso_codes_parser_init (); + parser.store = g_object_ref (store); xml_parser = gimp_xml_parser_new (&markup_parser, &parser); diff --git a/app/widgets/gimplanguagestore-parser.h b/app/widgets/gimplanguagestore-parser.h index 5fa091cb57..d84edd1ac3 100644 --- a/app/widgets/gimplanguagestore-parser.h +++ b/app/widgets/gimplanguagestore-parser.h @@ -2,7 +2,7 @@ * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * gimplanguagestore-parser.h - * Copyright (C) 2008 Sven Neumann + * Copyright (C) 2008, 2009 Sven Neumann * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,8 +22,8 @@ #define __GIMP_LANGUAGE_STORE_PARSER_H__ -gboolean gimp_language_store_populate (GimpLanguageStore *store, - GError **error); +gboolean gimp_language_store_parse_iso_codes (GimpLanguageStore *store, + GError **error); #endif /* __GIMP_LANGUAGE_STORE_PARSER_H__ */ diff --git a/app/widgets/gimplanguagestore.c b/app/widgets/gimplanguagestore.c index cb90ca1ad1..198f3cd4c7 100644 --- a/app/widgets/gimplanguagestore.c +++ b/app/widgets/gimplanguagestore.c @@ -2,7 +2,7 @@ * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * gimplanguagestore.c - * Copyright (C) 2008 Sven Neumann + * Copyright (C) 2008, 2009 Sven Neumann * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,11 +30,33 @@ #include "gimplanguagestore-parser.h" +static GObject * gimp_language_store_constructor (GType type, + guint n_params, + GObjectConstructParam *params); + +static void gimp_language_store_real_add (GimpLanguageStore *store, + const gchar *lang, + const gchar *code); + +static gint gimp_language_store_sort (GtkTreeModel *model, + GtkTreeIter *a, + GtkTreeIter *b, + gpointer userdata); + + G_DEFINE_TYPE (GimpLanguageStore, gimp_language_store, GTK_TYPE_LIST_STORE) +#define parent_class gimp_language_store_parent_class + + static void gimp_language_store_class_init (GimpLanguageStoreClass *klass) { + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructor = gimp_language_store_constructor; + + klass->add = gimp_language_store_real_add; } static void @@ -45,7 +67,81 @@ gimp_language_store_init (GimpLanguageStore *store) gtk_list_store_set_column_types (GTK_LIST_STORE (store), G_N_ELEMENTS (column_types), column_types); - gimp_language_store_populate (store, NULL); + gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store), + GIMP_LANGUAGE_STORE_LANGUAGE, + gimp_language_store_sort, NULL, NULL); + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), + GIMP_LANGUAGE_STORE_LANGUAGE, + GTK_SORT_ASCENDING); +} + +static GObject * +gimp_language_store_constructor (GType type, + guint n_params, + GObjectConstructParam *params) +{ + GObject *object; + + object = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params); + + gimp_language_store_parse_iso_codes (GIMP_LANGUAGE_STORE (object), NULL); + + return object; +} + +static void +gimp_language_store_real_add (GimpLanguageStore *store, + const gchar *lang, + const gchar *code) +{ + GtkTreeIter iter; + + gtk_list_store_append (GTK_LIST_STORE (store), &iter); + gtk_list_store_set (GTK_LIST_STORE (store), &iter, + GIMP_LANGUAGE_STORE_LANGUAGE, lang, + GIMP_LANGUAGE_STORE_ISO_639_1, code, + -1); +} + +static gint +gimp_language_store_sort (GtkTreeModel *model, + GtkTreeIter *a, + GtkTreeIter *b, + gpointer userdata) +{ + GValue avalue = { 0, }; + GValue bvalue = { 0, }; + gint cmp = 0; + + /* keep system language at the top of the list */ + gtk_tree_model_get_value (model, a, + GIMP_LANGUAGE_STORE_ISO_639_1, &avalue); + gtk_tree_model_get_value (model, b, + GIMP_LANGUAGE_STORE_ISO_639_1, &bvalue); + + if (! g_value_get_string (&avalue)) + cmp = -1; + + if (! g_value_get_string (&bvalue)) + cmp = 1; + + g_value_unset (&avalue); + g_value_unset (&bvalue); + + if (cmp) + return cmp; + + /* sort lanugages alphabetically */ + gtk_tree_model_get_value (model, a, GIMP_LANGUAGE_STORE_LANGUAGE, &avalue); + gtk_tree_model_get_value (model, b, GIMP_LANGUAGE_STORE_LANGUAGE, &bvalue); + + cmp = g_utf8_collate (g_value_get_string (&avalue), + g_value_get_string (&bvalue)); + + g_value_unset (&avalue); + g_value_unset (&bvalue); + + return cmp; } GtkListStore * @@ -59,17 +155,10 @@ gimp_language_store_add (GimpLanguageStore *store, const gchar *lang, const gchar *code) { - GtkTreeIter iter; - g_return_if_fail (GIMP_IS_LANGUAGE_STORE (store)); - g_return_if_fail (lang != NULL && code != NULL); + g_return_if_fail (lang != NULL); - gtk_list_store_append (GTK_LIST_STORE (store), &iter); - - gtk_list_store_set (GTK_LIST_STORE (store), &iter, - GIMP_LANGUAGE_STORE_LANGUAGE, lang, - GIMP_LANGUAGE_STORE_ISO_639_1, code, - -1); + GIMP_LANGUAGE_STORE_GET_CLASS (store)->add (store, lang, code); } gboolean @@ -108,7 +197,7 @@ gimp_language_store_lookup (GimpLanguageStore *store, GIMP_LANGUAGE_STORE_ISO_639_1, &value, -1); - if (strncmp (code, value, len) == 0) + if (value && strncmp (code, value, len) == 0) { g_free (value); break; diff --git a/app/widgets/gimplanguagestore.h b/app/widgets/gimplanguagestore.h index e316466c6b..51e9b8df1a 100644 --- a/app/widgets/gimplanguagestore.h +++ b/app/widgets/gimplanguagestore.h @@ -2,7 +2,7 @@ * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * gimplanguagestore.h - * Copyright (C) 2008 Sven Neumann + * Copyright (C) 2008, 2009 Sven Neumann * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -42,23 +42,30 @@ typedef struct _GimpLanguageStoreClass GimpLanguageStoreClass; struct _GimpLanguageStoreClass { GtkListStoreClass parent_class; + + void (* add) (GimpLanguageStore *store, + const gchar *lang, + const gchar *code); }; struct _GimpLanguageStore { - GtkListStore parent_instance; + GtkListStore parent_instance; }; GType gimp_language_store_get_type (void) G_GNUC_CONST; GtkListStore * gimp_language_store_new (void); -void gimp_language_store_add (GimpLanguageStore *store, - const gchar *lang, - const gchar *code); + gboolean gimp_language_store_lookup (GimpLanguageStore *store, const gchar *code, GtkTreeIter *iter); +/* used from gimplanguagestore-parser.c */ +void gimp_language_store_add (GimpLanguageStore *store, + const gchar *lang, + const gchar *code); + #endif /* __GIMP_LANGUAGE_STORE_H__ */ diff --git a/app/widgets/gimptranslationstore.c b/app/widgets/gimptranslationstore.c new file mode 100644 index 0000000000..f56c10be1e --- /dev/null +++ b/app/widgets/gimptranslationstore.c @@ -0,0 +1,196 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimptranslationstore.c + * Copyright (C) 2008, 2009 Sven Neumann + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "config.h" + +#include + +#include + +#include "libgimpbase/gimpbase.h" + +#include "widgets-types.h" + +#include "gimptranslationstore.h" + +#include "gimp-intl.h" + + +struct _GimpTranslationStoreClass +{ + GimpLanguageStoreClass parent_class; +}; + +struct _GimpTranslationStore +{ + GimpLanguageStore parent_instance; + + GHashTable *map; +}; + + +static GObject * gimp_translation_store_constructor (GType type, + guint n_params, + GObjectConstructParam *params); + +static void gimp_translation_store_add (GimpLanguageStore *store, + const gchar *lang, + const gchar *code); + +static void gimp_translation_store_populate (GimpTranslationStore *store); + + +G_DEFINE_TYPE (GimpTranslationStore, + gimp_translation_store, GIMP_TYPE_LANGUAGE_STORE) + +#define parent_class gimp_translation_store_parent_class + + +static void +gimp_translation_store_class_init (GimpTranslationStoreClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GimpLanguageStoreClass *store_class = GIMP_LANGUAGE_STORE_CLASS (klass); + + object_class->constructor = gimp_translation_store_constructor; + + store_class->add = gimp_translation_store_add; +} + +static void +gimp_translation_store_init (GimpTranslationStore *store) +{ + store->map = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) g_free); +} + +static GObject * +gimp_translation_store_constructor (GType type, + guint n_params, + GObjectConstructParam *params) +{ + GimpTranslationStore *store; + GObject *object; + gchar *label; + + object = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params); + store = GIMP_TRANSLATION_STORE (object); + + gimp_translation_store_populate (store); + + /* we don't need the map any longer */ + g_hash_table_unref (store->map); + store->map = NULL; + + /* add special entries for system locale and for "C" */ + GIMP_LANGUAGE_STORE_CLASS (parent_class)->add (GIMP_LANGUAGE_STORE (store), + _("System Language"), + NULL); + label = g_strdup_printf ("%s [%s]", _("English"), "en_US"); + GIMP_LANGUAGE_STORE_CLASS (parent_class)->add (GIMP_LANGUAGE_STORE (store), + label, "en_US"); + g_free (label); + + return object; +} + +static const gchar * +gimp_translation_store_map (GimpTranslationStore *store, + const gchar *locale) +{ + const gchar *lang; + + /* A locale directory name is typically of the form language[_territory] */ + lang = g_hash_table_lookup (store->map, locale); + + if (! lang) + { + /* strip off the territory suffix */ + const gchar *delimiter = strchr (locale, '_'); + + if (delimiter) + { + gchar *copy; + + copy = g_strndup (locale, delimiter - locale); + lang = g_hash_table_lookup (store->map, copy); + g_free (copy); + } + } + + return lang; +} + +static void +gimp_translation_store_populate (GimpTranslationStore *store) +{ + /* FIXME: this should better be done asynchronously */ + GDir *dir = g_dir_open (gimp_locale_directory (), 0, NULL); + const gchar *dirname; + + if (! dir) + return; + + while ((dirname = g_dir_read_name (dir)) != NULL) + { + gchar *filename = g_build_filename (gimp_locale_directory (), + dirname, + "LC_MESSAGES", + GETTEXT_PACKAGE ".mo", + NULL); + if (g_file_test (filename, G_FILE_TEST_EXISTS)) + { + const gchar *lang = gimp_translation_store_map (store, dirname); + + if (lang) + { + GimpLanguageStore *language_store = GIMP_LANGUAGE_STORE (store); + gchar *label; + + label = g_strdup_printf ("%s [%s]", lang, dirname); + + GIMP_LANGUAGE_STORE_CLASS (parent_class)->add (language_store, + label, dirname); + g_free (label); + } + } + + g_free (filename); + } + + g_dir_close (dir); +} + +static void +gimp_translation_store_add (GimpLanguageStore *store, + const gchar *lang, + const gchar *code) +{ + g_hash_table_replace (GIMP_TRANSLATION_STORE (store)->map, + g_strdup (code), + g_strdup (lang)); +} + +GtkListStore * +gimp_translation_store_new (void) +{ + return g_object_new (GIMP_TYPE_TRANSLATION_STORE, NULL); +} diff --git a/app/widgets/gimptranslationstore.h b/app/widgets/gimptranslationstore.h new file mode 100644 index 0000000000..83fb509e79 --- /dev/null +++ b/app/widgets/gimptranslationstore.h @@ -0,0 +1,44 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimptranslationstore.h + * Copyright (C) 2009 Sven Neumann + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __GIMP_TRANSLATION_STORE_H__ +#define __GIMP_TRANSLATION_STORE_H__ + + +#include "gimplanguagestore.h" + + +#define GIMP_TYPE_TRANSLATION_STORE (gimp_translation_store_get_type ()) +#define GIMP_TRANSLATION_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_TRANSLATION_STORE, GimpTranslationStore)) +#define GIMP_TRANSLATION_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_TRANSLATION_STORE, GimpTranslationStoreClass)) +#define GIMP_IS_TRANSLATION_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_TRANSLATION_STORE)) +#define GIMP_IS_TRANSLATION_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_TRANSLATION_STORE)) +#define GIMP_TRANSLATION_STORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_TRANSLATION_STORE, GimpTranslationStoreClass)) + + +typedef struct _GimpTranslationStoreClass GimpTranslationStoreClass; + + +GType gimp_translation_store_get_type (void) G_GNUC_CONST; + +GtkListStore * gimp_translation_store_new (void); + + +#endif /* __GIMP_TRANSLATION_STORE_H__ */ diff --git a/app/widgets/widgets-types.h b/app/widgets/widgets-types.h index 5301955173..bd7be48b46 100644 --- a/app/widgets/widgets-types.h +++ b/app/widgets/widgets-types.h @@ -188,6 +188,7 @@ typedef struct _GimpTagEntry GimpTagEntry; typedef struct _GimpTagPopup GimpTagPopup; typedef struct _GimpTemplateEditor GimpTemplateEditor; typedef struct _GimpThumbBox GimpThumbBox; +typedef struct _GimpTranslationStore GimpTranslationStore; typedef struct _GimpUnitStore GimpUnitStore; typedef struct _GimpUnitComboBox GimpUnitComboBox; typedef struct _GimpWindow GimpWindow;