Bug 704592 - only load language lists once at gui startup.
Improvements: - setenv/getenv() are not thread-safe, hence they should be run only at startup before any threading occurs. - it is counter-productive to load the huge ISO-639 XML file each time the user opens the Preferences dialog or the text tool options.
This commit is contained in:
@ -60,6 +60,7 @@
|
|||||||
#include "widgets/gimpsessioninfo.h"
|
#include "widgets/gimpsessioninfo.h"
|
||||||
#include "widgets/gimpuimanager.h"
|
#include "widgets/gimpuimanager.h"
|
||||||
#include "widgets/gimpwidgets-utils.h"
|
#include "widgets/gimpwidgets-utils.h"
|
||||||
|
#include "widgets/gimplanguagestore-parser.h"
|
||||||
|
|
||||||
#include "actions/actions.h"
|
#include "actions/actions.h"
|
||||||
#include "actions/windows-commands.h"
|
#include "actions/windows-commands.h"
|
||||||
@ -199,6 +200,7 @@ gui_init (Gimp *gimp,
|
|||||||
the_gui_gimp = gimp;
|
the_gui_gimp = gimp;
|
||||||
|
|
||||||
gui_unique_init (gimp);
|
gui_unique_init (gimp);
|
||||||
|
gimp_language_store_parser_init ();
|
||||||
|
|
||||||
gimp_widgets_init (gui_help_func,
|
gimp_widgets_init (gui_help_func,
|
||||||
gui_get_foreground_func,
|
gui_get_foreground_func,
|
||||||
@ -601,6 +603,8 @@ gui_exit_callback (Gimp *gimp,
|
|||||||
gimp_tools_save (gimp, gui_config->save_tool_options, FALSE);
|
gimp_tools_save (gimp, gui_config->save_tool_options, FALSE);
|
||||||
gimp_tools_exit (gimp);
|
gimp_tools_exit (gimp);
|
||||||
|
|
||||||
|
gimp_language_store_parser_clean ();
|
||||||
|
|
||||||
return FALSE; /* continue exiting */
|
return FALSE; /* continue exiting */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
*
|
*
|
||||||
* gimplanguagestore-parser.c
|
* gimplanguagestore-parser.c
|
||||||
* Copyright (C) 2008, 2009 Sven Neumann <sven@gimp.org>
|
* Copyright (C) 2008, 2009 Sven Neumann <sven@gimp.org>
|
||||||
|
* Copyright (C) 2013 Jehan <jehan at girinstud.io>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -50,10 +51,13 @@ typedef struct
|
|||||||
IsoCodesParserState state;
|
IsoCodesParserState state;
|
||||||
IsoCodesParserState last_known_state;
|
IsoCodesParserState last_known_state;
|
||||||
gint unknown_depth;
|
gint unknown_depth;
|
||||||
GimpLanguageStore *store;
|
GHashTable *base_lang_list;
|
||||||
} IsoCodesParser;
|
} IsoCodesParser;
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean parse_iso_codes (GHashTable *base_lang_list,
|
||||||
|
GError **error);
|
||||||
|
static void iso_codes_parser_init (void);
|
||||||
static void iso_codes_parser_start_element (GMarkupParseContext *context,
|
static void iso_codes_parser_start_element (GMarkupParseContext *context,
|
||||||
const gchar *element_name,
|
const gchar *element_name,
|
||||||
const gchar **attribute_names,
|
const gchar **attribute_names,
|
||||||
@ -68,10 +72,279 @@ static void iso_codes_parser_end_element (GMarkupParseContext *context,
|
|||||||
static void iso_codes_parser_start_unknown (IsoCodesParser *parser);
|
static void iso_codes_parser_start_unknown (IsoCodesParser *parser);
|
||||||
static void iso_codes_parser_end_unknown (IsoCodesParser *parser);
|
static void iso_codes_parser_end_unknown (IsoCodesParser *parser);
|
||||||
|
|
||||||
static void gimp_language_store_self_l10n (GimpLanguageStore *store,
|
/*
|
||||||
const gchar *lang,
|
* Language lists that we want to generate only once at program startup:
|
||||||
const gchar *code);
|
* @l10n_lang_list: all available localizations self-localized;
|
||||||
|
* @all_lang_list: all known languages, in the user-selected language.
|
||||||
|
*/
|
||||||
|
static GHashTable *l10n_lang_list = NULL;
|
||||||
|
static GHashTable *all_lang_list = NULL;
|
||||||
|
|
||||||
|
/********************\
|
||||||
|
* Public Functions *
|
||||||
|
\********************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize and run the language listing parser. This call must be
|
||||||
|
* made only once, at program initialization, but after language_init().
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gimp_language_store_parser_init (void)
|
||||||
|
{
|
||||||
|
GHashTable *base_lang_list;
|
||||||
|
gchar *current_env = g_strdup (g_getenv ("LANGUAGE"));
|
||||||
|
GDir *locales_dir;
|
||||||
|
GHashTableIter lang_iter;
|
||||||
|
gpointer key;
|
||||||
|
|
||||||
|
if (l10n_lang_list != NULL)
|
||||||
|
{
|
||||||
|
g_warning ("gimp_language_store_parser_init() must be run only once.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
l10n_lang_list = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||||
|
(GDestroyNotify) g_free,
|
||||||
|
(GDestroyNotify) g_free);
|
||||||
|
all_lang_list = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||||
|
(GDestroyNotify) g_free,
|
||||||
|
(GDestroyNotify) g_free);
|
||||||
|
base_lang_list = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||||
|
(GDestroyNotify) g_free,
|
||||||
|
(GDestroyNotify) g_free);
|
||||||
|
|
||||||
|
/* Check all locales we have translations for. */
|
||||||
|
locales_dir = g_dir_open (gimp_locale_directory (), 0, NULL);
|
||||||
|
if (locales_dir)
|
||||||
|
{
|
||||||
|
const gchar *locale;
|
||||||
|
|
||||||
|
while ((locale = g_dir_read_name (locales_dir)) != NULL)
|
||||||
|
{
|
||||||
|
gchar *filename = g_build_filename (gimp_locale_directory (),
|
||||||
|
locale,
|
||||||
|
"LC_MESSAGES",
|
||||||
|
GETTEXT_PACKAGE ".mo",
|
||||||
|
NULL);
|
||||||
|
if (g_file_test (filename, G_FILE_TEST_EXISTS))
|
||||||
|
{
|
||||||
|
gchar *delimiter = strchr (locale, '_');
|
||||||
|
gchar *base_code = NULL;
|
||||||
|
|
||||||
|
if (delimiter)
|
||||||
|
base_code = g_strndup (locale, delimiter - locale);
|
||||||
|
else
|
||||||
|
base_code = g_strdup (locale);
|
||||||
|
|
||||||
|
delimiter = strchr (base_code, '@');
|
||||||
|
|
||||||
|
if (delimiter)
|
||||||
|
{
|
||||||
|
gchar *temp = base_code;
|
||||||
|
base_code = g_strndup (base_code, delimiter - base_code);
|
||||||
|
g_free (temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save the full language code. */
|
||||||
|
g_hash_table_insert (l10n_lang_list, g_strdup (locale), NULL);
|
||||||
|
/* Save the base language code. */
|
||||||
|
g_hash_table_insert (base_lang_list, base_code, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_dir_close (locales_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse ISO-639 file to get full list of language and their names. */
|
||||||
|
parse_iso_codes (base_lang_list, NULL);
|
||||||
|
|
||||||
|
/* Generate the localized language names. */
|
||||||
|
g_hash_table_iter_init (&lang_iter, l10n_lang_list);
|
||||||
|
while (g_hash_table_iter_next (&lang_iter, &key, NULL))
|
||||||
|
{
|
||||||
|
gchar *code = GINT_TO_POINTER (key);
|
||||||
|
gchar *english_name;
|
||||||
|
gchar *delimiter = strchr (code, '_');
|
||||||
|
gchar *base_code;
|
||||||
|
|
||||||
|
if (delimiter)
|
||||||
|
base_code = g_strndup (code, delimiter - code);
|
||||||
|
else
|
||||||
|
base_code = g_strdup (code);
|
||||||
|
|
||||||
|
delimiter = strchr (base_code, '@');
|
||||||
|
|
||||||
|
if (delimiter)
|
||||||
|
{
|
||||||
|
gchar *temp = base_code;
|
||||||
|
base_code = g_strndup (base_code, delimiter - base_code);
|
||||||
|
g_free (temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
english_name = GINT_TO_POINTER (g_hash_table_lookup (base_lang_list, base_code));
|
||||||
|
|
||||||
|
if (english_name)
|
||||||
|
{
|
||||||
|
gchar *localized_name;
|
||||||
|
gchar *semicolon;
|
||||||
|
|
||||||
|
/* If possible, we want to localize a language in itself.
|
||||||
|
* If it fails, gettext fallbacks to C (en_US) itself.
|
||||||
|
*/
|
||||||
|
g_setenv ("LANGUAGE", code, TRUE);
|
||||||
|
setlocale (LC_ALL, "");
|
||||||
|
|
||||||
|
localized_name = g_strdup (dgettext ("iso_639", english_name));
|
||||||
|
|
||||||
|
/* If original and localized names are the same for other than English,
|
||||||
|
* maybe localization failed. Try now in the main dialect. */
|
||||||
|
if (g_strcmp0 (english_name, localized_name) == 0 &&
|
||||||
|
g_strcmp0 (base_code, "en") != 0 &&
|
||||||
|
g_strcmp0 (code, base_code) != 0)
|
||||||
|
{
|
||||||
|
g_free (localized_name);
|
||||||
|
|
||||||
|
g_setenv ("LANGUAGE", base_code, TRUE);
|
||||||
|
setlocale (LC_ALL, "");
|
||||||
|
|
||||||
|
localized_name = g_strdup (dgettext ("iso_639", english_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* there might be several language names; use the first one */
|
||||||
|
semicolon = strchr (localized_name, ';');
|
||||||
|
|
||||||
|
if (semicolon)
|
||||||
|
{
|
||||||
|
gchar *temp = localized_name;
|
||||||
|
localized_name = g_strndup (localized_name, semicolon - localized_name);
|
||||||
|
g_free (temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_hash_table_replace (l10n_lang_list, g_strdup(code),
|
||||||
|
g_strdup_printf ("%s [%s]",
|
||||||
|
localized_name ?
|
||||||
|
localized_name : "???",
|
||||||
|
code));
|
||||||
|
g_free (localized_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (base_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add special entries for system locale.
|
||||||
|
* We want the system locale to be localized in itself. */
|
||||||
|
g_setenv ("LANGUAGE", setlocale (LC_ALL, NULL), TRUE);
|
||||||
|
setlocale (LC_ALL, "");
|
||||||
|
|
||||||
|
/* g_str_hash() does not accept NULL. I give an empty code instead.
|
||||||
|
* Other solution would to create a custom hash. */
|
||||||
|
g_hash_table_insert (l10n_lang_list, g_strdup(""),
|
||||||
|
g_strdup (_("System Language")));
|
||||||
|
|
||||||
|
/* Go back to original localization. */
|
||||||
|
if (current_env)
|
||||||
|
{
|
||||||
|
g_setenv ("LANGUAGE", current_env, TRUE);
|
||||||
|
g_free (current_env);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
g_unsetenv ("LANGUAGE");
|
||||||
|
setlocale (LC_ALL, "");
|
||||||
|
|
||||||
|
/* Add special entry for C (en_US). */
|
||||||
|
g_hash_table_insert (l10n_lang_list, g_strdup ("en_US"),
|
||||||
|
g_strdup ("English [en_US]"));
|
||||||
|
|
||||||
|
g_hash_table_destroy (base_lang_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gimp_language_store_parser_clean (void)
|
||||||
|
{
|
||||||
|
g_hash_table_destroy (l10n_lang_list);
|
||||||
|
g_hash_table_destroy (all_lang_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns a Hash table of languages.
|
||||||
|
* Keys and values are respectively language codes and names from the
|
||||||
|
* ISO-639 standard code.
|
||||||
|
*
|
||||||
|
* If @localization_only is TRUE, it returns only the list of available
|
||||||
|
* GIMP localizations, and language names are translated in their own
|
||||||
|
* locale.
|
||||||
|
* If @localization_only is FALSE, the full list of ISO-639 languages
|
||||||
|
* is returned, and language names are in the user-set locale.
|
||||||
|
*
|
||||||
|
* Do not free the list or elements of the list.
|
||||||
|
*/
|
||||||
|
GHashTable *
|
||||||
|
gimp_language_store_parser_get_languages (gboolean localization_only)
|
||||||
|
{
|
||||||
|
if (localization_only)
|
||||||
|
return l10n_lang_list;
|
||||||
|
else
|
||||||
|
return all_lang_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************\
|
||||||
|
* Private Parsing Functions *
|
||||||
|
\*****************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse the ISO-639 code list if available on this system, and fill
|
||||||
|
* @base_lang_list with English names of all needed base codes.
|
||||||
|
*
|
||||||
|
* It will also fill the static @all_lang_list.
|
||||||
|
*/
|
||||||
|
static gboolean
|
||||||
|
parse_iso_codes (GHashTable *base_lang_list,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean success = TRUE;
|
||||||
|
#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;
|
||||||
|
IsoCodesParser parser = { 0, };
|
||||||
|
|
||||||
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||||
|
|
||||||
|
iso_codes_parser_init ();
|
||||||
|
|
||||||
|
parser.base_lang_list = g_hash_table_ref (base_lang_list);
|
||||||
|
|
||||||
|
xml_parser = gimp_xml_parser_new (&markup_parser, &parser);
|
||||||
|
|
||||||
|
#ifdef G_OS_WIN32
|
||||||
|
filename = g_build_filename (gimp_data_directory (),
|
||||||
|
"..", "..", "xml", "iso-codes", "iso_639.xml",
|
||||||
|
NULL);
|
||||||
|
#else
|
||||||
|
filename = g_build_filename (ISO_CODES_LOCATION, "iso_639.xml", NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
success = gimp_xml_parser_parse_file (xml_parser, filename, error);
|
||||||
|
|
||||||
|
g_free (filename);
|
||||||
|
|
||||||
|
gimp_xml_parser_free (xml_parser);
|
||||||
|
g_hash_table_unref (parser.base_lang_list);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
iso_codes_parser_init (void)
|
iso_codes_parser_init (void)
|
||||||
@ -93,55 +366,6 @@ iso_codes_parser_init (void)
|
|||||||
initialized = TRUE;
|
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);
|
|
||||||
|
|
||||||
#ifdef G_OS_WIN32
|
|
||||||
filename = g_build_filename (gimp_data_directory (),
|
|
||||||
"..", "..", "xml", "iso-codes", "iso_639.xml",
|
|
||||||
NULL);
|
|
||||||
#else
|
|
||||||
filename = g_build_filename (ISO_CODES_LOCATION, "iso_639.xml", NULL);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
success = gimp_xml_parser_parse_file (xml_parser, filename, error);
|
|
||||||
|
|
||||||
g_free (filename);
|
|
||||||
|
|
||||||
gimp_xml_parser_free (xml_parser);
|
|
||||||
g_object_unref (parser.store);
|
|
||||||
|
|
||||||
return success;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
iso_codes_parser_entry (IsoCodesParser *parser,
|
iso_codes_parser_entry (IsoCodesParser *parser,
|
||||||
const gchar **names,
|
const gchar **names,
|
||||||
@ -153,101 +377,41 @@ iso_codes_parser_entry (IsoCodesParser *parser,
|
|||||||
while (*names && *values)
|
while (*names && *values)
|
||||||
{
|
{
|
||||||
if (strcmp (*names, "name") == 0)
|
if (strcmp (*names, "name") == 0)
|
||||||
{
|
|
||||||
lang = *values;
|
lang = *values;
|
||||||
}
|
|
||||||
else if (strcmp (*names, "iso_639_2B_code") == 0 && code == NULL)
|
else if (strcmp (*names, "iso_639_2B_code") == 0 && code == NULL)
|
||||||
{
|
|
||||||
/* 2-letter ISO 639-1 codes have priority.
|
/* 2-letter ISO 639-1 codes have priority.
|
||||||
* But some languages have no 2-letter code.
|
* But some languages have no 2-letter code. Ex: Asturian (ast).
|
||||||
* Ex: Asturian (ast).
|
|
||||||
*/
|
*/
|
||||||
code = *values;
|
code = *values;
|
||||||
}
|
|
||||||
else if (strcmp (*names, "iso_639_2T_code") == 0 && code == NULL)
|
else if (strcmp (*names, "iso_639_2T_code") == 0 && code == NULL)
|
||||||
{
|
|
||||||
code = *values;
|
code = *values;
|
||||||
}
|
|
||||||
else if (strcmp (*names, "iso_639_1_code") == 0)
|
else if (strcmp (*names, "iso_639_1_code") == 0)
|
||||||
{
|
|
||||||
code = *values;
|
code = *values;
|
||||||
}
|
|
||||||
|
|
||||||
names++;
|
names++;
|
||||||
values++;
|
values++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is a hack for some special exception.
|
|
||||||
* It seems localization won't work for the base language "zh". Probably because
|
|
||||||
* written locale dialect are too different. So we have to be accurate and localize
|
|
||||||
* separately each Chinese dialect we support.
|
|
||||||
*
|
|
||||||
* There was unfortunately no cleaner way to achieve this since there is no standardized
|
|
||||||
* link between regions in iso-3166 and base languages in iso-639, which would allow
|
|
||||||
* automatization for generating locale dialects codes.
|
|
||||||
*/
|
|
||||||
if (g_strcmp0 (code, "zh") == 0)
|
|
||||||
{
|
|
||||||
gimp_language_store_self_l10n (parser->store, "Chinese", "zh_CN");
|
|
||||||
gimp_language_store_self_l10n (parser->store, "Chinese", "zh_TW");
|
|
||||||
gimp_language_store_self_l10n (parser->store, "Chinese", "zh_HK");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
gimp_language_store_self_l10n (parser->store, lang, code);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If possible, we want to localize a language in itself.
|
|
||||||
* If it fails, fallback to the currently selected language, then to system lang.
|
|
||||||
* Only fallback to C (en_US) as a last resort.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
gimp_language_store_self_l10n (GimpLanguageStore *store,
|
|
||||||
const gchar *lang,
|
|
||||||
const gchar *code)
|
|
||||||
{
|
|
||||||
if (lang && *lang && code && *code)
|
if (lang && *lang && code && *code)
|
||||||
{
|
{
|
||||||
const gchar *semicolon;
|
gchar *semicolon;
|
||||||
|
gchar *localized_name = g_strdup (dgettext ("iso_639", lang));
|
||||||
|
|
||||||
/* English does not need localization. */
|
/* If the language is in our base table, we save its standard English name. */
|
||||||
if (g_strcmp0 (code, "en") != 0)
|
if (g_hash_table_contains (parser->base_lang_list, code))
|
||||||
{
|
g_hash_table_replace (parser->base_lang_list, g_strdup (code), g_strdup (lang));
|
||||||
gchar *current_lang = g_strdup (g_getenv ("LANGUAGE"));
|
|
||||||
gchar *temp_lang;
|
|
||||||
|
|
||||||
if (current_lang)
|
|
||||||
temp_lang = g_strdup_printf ("%s:%s:%s", code, current_lang, setlocale (LC_ALL, NULL));
|
|
||||||
else
|
|
||||||
temp_lang = g_strdup (code);
|
|
||||||
|
|
||||||
/* Temporarily change the localization language. */
|
|
||||||
g_setenv ("LANGUAGE", temp_lang, TRUE);
|
|
||||||
setlocale (LC_ALL, "");
|
|
||||||
lang = dgettext ("iso_639", lang);
|
|
||||||
if (current_lang)
|
|
||||||
g_setenv ("LANGUAGE", current_lang, TRUE);
|
|
||||||
else
|
|
||||||
g_unsetenv("LANGUAGE");
|
|
||||||
setlocale (LC_ALL, "");
|
|
||||||
|
|
||||||
g_free (current_lang);
|
|
||||||
g_free (temp_lang);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* there might be several language names; use the first one */
|
/* there might be several language names; use the first one */
|
||||||
semicolon = strchr (lang, ';');
|
semicolon = strchr (localized_name, ';');
|
||||||
|
|
||||||
if (semicolon)
|
if (semicolon)
|
||||||
{
|
{
|
||||||
gchar *first = g_strndup (lang, semicolon - lang);
|
gchar *temp = localized_name;
|
||||||
|
localized_name = g_strndup (localized_name, semicolon - localized_name);
|
||||||
gimp_language_store_add (store, first, code);
|
g_free (temp);
|
||||||
g_free (first);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gimp_language_store_add (store, lang, code);
|
|
||||||
}
|
}
|
||||||
|
/* In any case, we save the name in user-set language for all lang. */
|
||||||
|
g_hash_table_insert (all_lang_list, g_strdup (code), localized_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
*
|
*
|
||||||
* gimplanguagestore-parser.h
|
* gimplanguagestore-parser.h
|
||||||
* Copyright (C) 2008, 2009 Sven Neumann <sven@gimp.org>
|
* Copyright (C) 2008, 2009 Sven Neumann <sven@gimp.org>
|
||||||
|
* Copyright (C) 2013 Jehan <jehan at girinstud.io>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -22,8 +23,10 @@
|
|||||||
#define __GIMP_LANGUAGE_STORE_PARSER_H__
|
#define __GIMP_LANGUAGE_STORE_PARSER_H__
|
||||||
|
|
||||||
|
|
||||||
gboolean gimp_language_store_parse_iso_codes (GimpLanguageStore *store,
|
void gimp_language_store_parser_init (void);
|
||||||
GError **error);
|
|
||||||
|
|
||||||
|
void gimp_language_store_parser_clean (void);
|
||||||
|
|
||||||
|
GHashTable* gimp_language_store_parser_get_languages (gboolean localization_only);
|
||||||
|
|
||||||
#endif /* __GIMP_LANGUAGE_STORE_PARSER_H__ */
|
#endif /* __GIMP_LANGUAGE_STORE_PARSER_H__ */
|
||||||
|
@ -76,9 +76,20 @@ gimp_language_store_init (GimpLanguageStore *store)
|
|||||||
static void
|
static void
|
||||||
gimp_language_store_constructed (GObject *object)
|
gimp_language_store_constructed (GObject *object)
|
||||||
{
|
{
|
||||||
|
GHashTable *lang_list;
|
||||||
|
GHashTableIter lang_iter;
|
||||||
|
gpointer code;
|
||||||
|
gpointer name;
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->constructed (object);
|
G_OBJECT_CLASS (parent_class)->constructed (object);
|
||||||
|
|
||||||
gimp_language_store_parse_iso_codes (GIMP_LANGUAGE_STORE (object), NULL);
|
lang_list = gimp_language_store_parser_get_languages (FALSE);
|
||||||
|
g_hash_table_iter_init (&lang_iter, lang_list);
|
||||||
|
|
||||||
|
while (g_hash_table_iter_next (&lang_iter, &code, &name))
|
||||||
|
GIMP_LANGUAGE_STORE_GET_CLASS (object)->add (GIMP_LANGUAGE_STORE (object),
|
||||||
|
GINT_TO_POINTER (name),
|
||||||
|
GINT_TO_POINTER (code));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -109,10 +120,10 @@ gimp_language_store_sort (GtkTreeModel *model,
|
|||||||
gtk_tree_model_get_value (model, a, GIMP_LANGUAGE_STORE_CODE, &avalue);
|
gtk_tree_model_get_value (model, a, GIMP_LANGUAGE_STORE_CODE, &avalue);
|
||||||
gtk_tree_model_get_value (model, b, GIMP_LANGUAGE_STORE_CODE, &bvalue);
|
gtk_tree_model_get_value (model, b, GIMP_LANGUAGE_STORE_CODE, &bvalue);
|
||||||
|
|
||||||
if (! g_value_get_string (&avalue))
|
if (g_strcmp0 ("", g_value_get_string (&avalue)) == 0)
|
||||||
cmp = -1;
|
cmp = -1;
|
||||||
|
|
||||||
if (! g_value_get_string (&bvalue))
|
if (g_strcmp0 ("", g_value_get_string (&bvalue)) == 0)
|
||||||
cmp = 1;
|
cmp = 1;
|
||||||
|
|
||||||
g_value_unset (&avalue);
|
g_value_unset (&avalue);
|
||||||
@ -140,17 +151,6 @@ gimp_language_store_new (void)
|
|||||||
return g_object_new (GIMP_TYPE_LANGUAGE_STORE, NULL);
|
return g_object_new (GIMP_TYPE_LANGUAGE_STORE, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
gimp_language_store_add (GimpLanguageStore *store,
|
|
||||||
const gchar *label,
|
|
||||||
const gchar *code)
|
|
||||||
{
|
|
||||||
g_return_if_fail (GIMP_IS_LANGUAGE_STORE (store));
|
|
||||||
g_return_if_fail (label != NULL);
|
|
||||||
|
|
||||||
GIMP_LANGUAGE_STORE_GET_CLASS (store)->add (store, label, code);
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gimp_language_store_lookup (GimpLanguageStore *store,
|
gimp_language_store_lookup (GimpLanguageStore *store,
|
||||||
const gchar *code,
|
const gchar *code,
|
||||||
|
@ -62,10 +62,4 @@ gboolean gimp_language_store_lookup (GimpLanguageStore *store,
|
|||||||
const gchar *code,
|
const gchar *code,
|
||||||
GtkTreeIter *iter);
|
GtkTreeIter *iter);
|
||||||
|
|
||||||
/* used from gimplanguagestore-parser.c */
|
|
||||||
void gimp_language_store_add (GimpLanguageStore *store,
|
|
||||||
const gchar *label,
|
|
||||||
const gchar *code);
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* __GIMP_LANGUAGE_STORE_H__ */
|
#endif /* __GIMP_LANGUAGE_STORE_H__ */
|
||||||
|
@ -18,8 +18,6 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@ -31,8 +29,6 @@
|
|||||||
|
|
||||||
#include "gimptranslationstore.h"
|
#include "gimptranslationstore.h"
|
||||||
|
|
||||||
#include "gimp-intl.h"
|
|
||||||
|
|
||||||
|
|
||||||
struct _GimpTranslationStoreClass
|
struct _GimpTranslationStoreClass
|
||||||
{
|
{
|
||||||
@ -42,19 +38,11 @@ struct _GimpTranslationStoreClass
|
|||||||
struct _GimpTranslationStore
|
struct _GimpTranslationStore
|
||||||
{
|
{
|
||||||
GimpLanguageStore parent_instance;
|
GimpLanguageStore parent_instance;
|
||||||
|
|
||||||
GHashTable *map;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void gimp_translation_store_constructed (GObject *object);
|
static void gimp_translation_store_constructed (GObject *object);
|
||||||
|
|
||||||
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,
|
G_DEFINE_TYPE (GimpTranslationStore, gimp_translation_store,
|
||||||
GIMP_TYPE_LANGUAGE_STORE)
|
GIMP_TYPE_LANGUAGE_STORE)
|
||||||
@ -66,134 +54,30 @@ static void
|
|||||||
gimp_translation_store_class_init (GimpTranslationStoreClass *klass)
|
gimp_translation_store_class_init (GimpTranslationStoreClass *klass)
|
||||||
{
|
{
|
||||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
GimpLanguageStoreClass *store_class = GIMP_LANGUAGE_STORE_CLASS (klass);
|
|
||||||
|
|
||||||
object_class->constructed = gimp_translation_store_constructed;
|
object_class->constructed = gimp_translation_store_constructed;
|
||||||
|
|
||||||
store_class->add = gimp_translation_store_add;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gimp_translation_store_init (GimpTranslationStore *store)
|
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 void
|
static void
|
||||||
gimp_translation_store_constructed (GObject *object)
|
gimp_translation_store_constructed (GObject *object)
|
||||||
{
|
{
|
||||||
GimpTranslationStore *store = GIMP_TRANSLATION_STORE (object);
|
GHashTable *lang_list;
|
||||||
gchar *current_lang = g_strdup (g_getenv ("LANGUAGE"));
|
GHashTableIter lang_iter;
|
||||||
gchar *label;
|
gpointer code;
|
||||||
|
gpointer name;
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->constructed (object);
|
lang_list = gimp_language_store_parser_get_languages (TRUE);
|
||||||
|
g_hash_table_iter_init (&lang_iter, lang_list);
|
||||||
|
|
||||||
gimp_translation_store_populate (store);
|
while (g_hash_table_iter_next (&lang_iter, &code, &name))
|
||||||
|
GIMP_LANGUAGE_STORE_GET_CLASS (object)->add (GIMP_LANGUAGE_STORE (object),
|
||||||
/* we don't need the map any longer */
|
GINT_TO_POINTER (name),
|
||||||
g_hash_table_unref (store->map);
|
GINT_TO_POINTER (code));
|
||||||
store->map = NULL;
|
|
||||||
|
|
||||||
/* add special entries for system locale and for "C".
|
|
||||||
* We want the system locale to be localized in itself. */
|
|
||||||
g_setenv ("LANGUAGE", setlocale (LC_ALL, NULL), TRUE);
|
|
||||||
setlocale (LC_ALL, "");
|
|
||||||
label = g_strdup_printf ("%s", _("System Language"));
|
|
||||||
if (current_lang)
|
|
||||||
g_setenv ("LANGUAGE", current_lang, TRUE);
|
|
||||||
else
|
|
||||||
g_unsetenv ("LANGUAGE");
|
|
||||||
setlocale (LC_ALL, "");
|
|
||||||
g_free (current_lang);
|
|
||||||
|
|
||||||
GIMP_LANGUAGE_STORE_CLASS (parent_class)->add (GIMP_LANGUAGE_STORE (store),
|
|
||||||
label,
|
|
||||||
NULL);
|
|
||||||
g_free (label);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 *
|
GtkListStore *
|
||||||
|
Reference in New Issue
Block a user