2008-02-08 00:50:11 +08:00
|
|
|
/* GIMP - The GNU Image Manipulation Program
|
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
|
|
*
|
2024-08-10 08:02:49 +08:00
|
|
|
* gen-languages.c (formerly gimplanguagestore-parser.c)
|
2009-12-31 06:55:26 +08:00
|
|
|
* Copyright (C) 2008, 2009 Sven Neumann <sven@gimp.org>
|
2024-08-10 08:02:49 +08:00
|
|
|
* Copyright (C) 2013, 2024 Jehan <jehan at girinstud.io>
|
2008-02-08 00:50:11 +08:00
|
|
|
*
|
2009-01-18 06:28:01 +08:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
2008-02-08 00:50:11 +08:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
2009-01-18 06:28:01 +08:00
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
2008-02-08 00:50:11 +08:00
|
|
|
* (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
|
2018-07-12 05:27:07 +08:00
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2008-02-08 00:50:11 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2013-07-22 09:12:41 +08:00
|
|
|
#include <locale.h>
|
2008-02-08 00:50:11 +08:00
|
|
|
#include <string.h>
|
|
|
|
|
2024-08-10 08:02:49 +08:00
|
|
|
#include <gio/gio.h>
|
|
|
|
#include <glib.h>
|
2008-02-08 00:50:11 +08:00
|
|
|
|
2008-06-28 21:55:24 +08:00
|
|
|
#include "libgimpbase/gimpbase.h"
|
2008-02-12 07:10:58 +08:00
|
|
|
|
2024-08-10 08:02:49 +08:00
|
|
|
#include "config/config-types.h"
|
2008-02-08 00:50:11 +08:00
|
|
|
#include "config/gimpxmlparser.h"
|
|
|
|
|
2008-02-08 21:50:34 +08:00
|
|
|
#include "gimp-intl.h"
|
|
|
|
|
2024-08-14 21:48:37 +08:00
|
|
|
#define PRINT(...) if (! g_output_stream_printf (output, NULL, NULL, &error, __VA_ARGS__))\
|
|
|
|
{\
|
|
|
|
g_printerr ("ERROR: %s\n", error->message);\
|
|
|
|
g_object_unref (output);\
|
|
|
|
exit (EXIT_FAILURE);\
|
|
|
|
}
|
|
|
|
|
2008-02-08 00:50:11 +08:00
|
|
|
|
|
|
|
typedef enum
|
|
|
|
{
|
|
|
|
ISO_CODES_START,
|
|
|
|
ISO_CODES_IN_ENTRIES,
|
|
|
|
ISO_CODES_IN_ENTRY,
|
|
|
|
ISO_CODES_IN_UNKNOWN
|
|
|
|
} IsoCodesParserState;
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
IsoCodesParserState state;
|
|
|
|
IsoCodesParserState last_known_state;
|
|
|
|
gint unknown_depth;
|
2013-07-20 13:51:13 +08:00
|
|
|
GHashTable *base_lang_list;
|
2008-02-08 00:50:11 +08:00
|
|
|
} IsoCodesParser;
|
|
|
|
|
|
|
|
|
2024-08-14 21:48:37 +08:00
|
|
|
static gboolean gimp_language_store_parser_init (GError **error);
|
2024-08-10 08:02:49 +08:00
|
|
|
static void gimp_language_store_parser_clean (void);
|
|
|
|
|
2013-07-20 13:51:13 +08:00
|
|
|
static gboolean parse_iso_codes (GHashTable *base_lang_list,
|
|
|
|
GError **error);
|
2015-01-10 07:03:04 +08:00
|
|
|
|
|
|
|
#ifdef HAVE_ISO_CODES
|
2013-07-20 13:51:13 +08:00
|
|
|
static void iso_codes_parser_init (void);
|
|
|
|
static void iso_codes_parser_start_element (GMarkupParseContext *context,
|
|
|
|
const gchar *element_name,
|
|
|
|
const gchar **attribute_names,
|
|
|
|
const gchar **attribute_values,
|
|
|
|
gpointer user_data,
|
|
|
|
GError **error);
|
|
|
|
static void iso_codes_parser_end_element (GMarkupParseContext *context,
|
|
|
|
const gchar *element_name,
|
|
|
|
gpointer user_data,
|
|
|
|
GError **error);
|
|
|
|
|
|
|
|
static void iso_codes_parser_start_unknown (IsoCodesParser *parser);
|
|
|
|
static void iso_codes_parser_end_unknown (IsoCodesParser *parser);
|
2015-01-10 07:03:04 +08:00
|
|
|
#endif /* HAVE_ISO_CODES */
|
2013-07-20 13:51:13 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Language lists that we want to generate only once at program startup:
|
|
|
|
* @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;
|
2008-02-08 00:50:11 +08:00
|
|
|
|
2013-07-20 13:51:13 +08:00
|
|
|
/********************\
|
|
|
|
* Public Functions *
|
|
|
|
\********************/
|
2008-02-08 00:50:11 +08:00
|
|
|
|
2024-08-10 08:02:49 +08:00
|
|
|
int
|
|
|
|
main (int argc,
|
|
|
|
char **argv)
|
|
|
|
{
|
|
|
|
GFile *outfile;
|
|
|
|
GOutputStream *output;
|
|
|
|
GHashTableIter lang_iter;
|
|
|
|
GError *error = NULL;
|
|
|
|
gpointer code;
|
|
|
|
gpointer name;
|
|
|
|
const gchar *license_header = "\
|
|
|
|
/* GIMP - The GNU Image Manipulation Program\n\
|
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis\n\
|
|
|
|
*\n\
|
|
|
|
* gimplanguagestore-data.h\n\
|
|
|
|
* Copyright (C) 2024 Jehan\n\
|
|
|
|
*\n\
|
|
|
|
* This program is free software: you can redistribute it and/or modify\n\
|
|
|
|
* it under the terms of the GNU General Public License as published by\n\
|
|
|
|
* the Free Software Foundation; either version 3 of the License, or\n\
|
|
|
|
* (at your option) any later version.\n\
|
|
|
|
*\n\
|
|
|
|
* This program is distributed in the hope that it will be useful,\n\
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\
|
|
|
|
* GNU General Public License for more details.\n\
|
|
|
|
*\n\
|
|
|
|
* You should have received a copy of the GNU General Public License\n\
|
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.\n\
|
|
|
|
*/\n";
|
|
|
|
|
2024-08-14 21:48:37 +08:00
|
|
|
if (! gimp_language_store_parser_init (&error))
|
|
|
|
{
|
|
|
|
g_printerr ("ERROR: %s\n", error->message);
|
|
|
|
exit (EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
2024-08-10 08:02:49 +08:00
|
|
|
outfile = g_file_new_build_filename (argv[0], "../../app/widgets/gimplanguagestore-data.h", NULL);
|
|
|
|
output = G_OUTPUT_STREAM (g_file_replace (outfile,
|
|
|
|
NULL, FALSE, G_FILE_CREATE_NONE,
|
|
|
|
NULL, &error));
|
|
|
|
g_object_unref (outfile);
|
|
|
|
|
2024-08-14 21:48:37 +08:00
|
|
|
if (! output)
|
|
|
|
{
|
|
|
|
g_printerr ("ERROR: %s\n", error->message);
|
|
|
|
g_object_unref (output);
|
|
|
|
exit (EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRINT ("%s", license_header);
|
|
|
|
PRINT ("\n/* NOTE: this file is auto-generated by %s */\n\n", argv[0]);
|
2024-08-10 08:02:49 +08:00
|
|
|
|
|
|
|
g_hash_table_iter_init (&lang_iter, l10n_lang_list);
|
|
|
|
|
2024-08-14 21:48:37 +08:00
|
|
|
PRINT ("#define GIMP_L10N_LANGS_SIZE %d\n", g_hash_table_size (l10n_lang_list));
|
|
|
|
PRINT ("#define GIMP_ALL_LANGS_SIZE %d\n", g_hash_table_size (all_lang_list));
|
|
|
|
PRINT ("\ntypedef struct"
|
|
|
|
"\n{"
|
|
|
|
"\n gchar *code;"
|
|
|
|
"\n gchar *name;"
|
|
|
|
"\n} GimpLanguageDef;\n");
|
|
|
|
|
|
|
|
PRINT ("\nstatic const GimpLanguageDef GimpL10nLanguages[GIMP_L10N_LANGS_SIZE] =\n{\n");
|
2024-08-10 08:02:49 +08:00
|
|
|
while (g_hash_table_iter_next (&lang_iter, &code, &name))
|
2024-08-14 21:48:37 +08:00
|
|
|
PRINT (" { \"%s\", \"%s\" },\n", (gchar *) code, (gchar *) name);
|
|
|
|
PRINT ("};\n");
|
2024-08-10 08:02:49 +08:00
|
|
|
|
|
|
|
g_hash_table_iter_init (&lang_iter, all_lang_list);
|
2024-08-14 21:48:37 +08:00
|
|
|
PRINT ("\n\nstatic const GimpLanguageDef GimpAllLanguages[GIMP_ALL_LANGS_SIZE] =\n{\n");
|
2024-08-10 08:02:49 +08:00
|
|
|
while (g_hash_table_iter_next (&lang_iter, &code, &name))
|
2024-08-14 21:48:37 +08:00
|
|
|
PRINT (" { \"%s\", \"%s\" },\n", (gchar *) code, (gchar *) name);
|
|
|
|
PRINT ("};\n");
|
2024-08-10 08:02:49 +08:00
|
|
|
|
|
|
|
gimp_language_store_parser_clean ();
|
|
|
|
|
|
|
|
if (! g_output_stream_close (output, NULL, &error))
|
|
|
|
{
|
|
|
|
g_printerr ("ERROR: %s\n", error->message);
|
|
|
|
g_object_unref (output);
|
|
|
|
exit (EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
g_object_unref (output);
|
|
|
|
exit (EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2013-07-20 13:51:13 +08:00
|
|
|
/*
|
|
|
|
* Initialize and run the language listing parser. This call must be
|
|
|
|
* made only once, at program initialization, but after language_init().
|
|
|
|
*/
|
2024-08-14 21:48:37 +08:00
|
|
|
static gboolean
|
|
|
|
gimp_language_store_parser_init (GError **error)
|
2013-07-20 13:51:13 +08:00
|
|
|
{
|
2024-08-15 06:02:32 +08:00
|
|
|
GTimer *timer = g_timer_new ();
|
|
|
|
GInputStream *input = NULL;
|
|
|
|
GDataInputStream *dinput = NULL;
|
|
|
|
GHashTable *base_lang_list;
|
|
|
|
gchar *current_env;
|
|
|
|
GFile *linguas;
|
|
|
|
GHashTableIter lang_iter;
|
|
|
|
gpointer key;
|
|
|
|
gchar *locale;
|
|
|
|
gint n_locales = 0;
|
|
|
|
gint n_mo = 0;
|
|
|
|
gboolean success = TRUE;
|
2013-07-03 10:58:16 +08:00
|
|
|
|
2013-07-20 13:51:13 +08:00
|
|
|
if (l10n_lang_list != NULL)
|
|
|
|
{
|
2024-08-14 21:48:37 +08:00
|
|
|
g_set_error_literal (error, G_IO_ERROR, 0,
|
|
|
|
"gimp_language_store_parser_init() must be run only once.");
|
|
|
|
return FALSE;
|
2013-07-20 13:51:13 +08:00
|
|
|
}
|
2008-02-08 00:50:11 +08:00
|
|
|
|
2014-04-30 06:36:00 +08:00
|
|
|
current_env = g_strdup (g_getenv ("LANGUAGE"));
|
|
|
|
|
2013-07-20 13:51:13 +08:00
|
|
|
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. */
|
2024-08-15 06:02:32 +08:00
|
|
|
linguas = g_file_new_build_filename (SRCDIR, "po", "LINGUAS", NULL);
|
|
|
|
input = G_INPUT_STREAM (g_file_read (linguas, NULL, error));
|
|
|
|
if (! input)
|
2013-07-20 13:51:13 +08:00
|
|
|
{
|
2024-08-15 06:02:32 +08:00
|
|
|
success = FALSE;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2008-02-08 00:50:11 +08:00
|
|
|
|
2024-08-15 06:02:32 +08:00
|
|
|
dinput = g_data_input_stream_new (input);
|
2013-07-20 13:51:13 +08:00
|
|
|
|
2024-08-15 06:02:32 +08:00
|
|
|
while ((locale = g_data_input_stream_read_line (dinput, NULL, NULL, error)))
|
|
|
|
{
|
|
|
|
g_strstrip (locale);
|
2013-07-28 22:12:17 +08:00
|
|
|
|
2024-08-15 06:02:32 +08:00
|
|
|
if (strlen (locale) > 0 && locale[0] != '#')
|
|
|
|
{
|
|
|
|
gchar *delimiter = NULL;
|
|
|
|
gchar *base_code = NULL;
|
2013-07-20 13:51:13 +08:00
|
|
|
|
2024-08-15 06:02:32 +08:00
|
|
|
delimiter = strchr (locale, '_');
|
2013-07-20 13:51:13 +08:00
|
|
|
|
2024-08-15 06:02:32 +08:00
|
|
|
if (delimiter)
|
|
|
|
base_code = g_strndup (locale, delimiter - locale);
|
|
|
|
else
|
|
|
|
base_code = g_strdup (locale);
|
2013-07-20 13:51:13 +08:00
|
|
|
|
2024-08-15 06:02:32 +08:00
|
|
|
delimiter = strchr (base_code, '@');
|
2024-08-14 21:48:37 +08:00
|
|
|
|
2024-08-15 06:02:32 +08:00
|
|
|
if (delimiter)
|
|
|
|
{
|
|
|
|
gchar *temp = base_code;
|
|
|
|
base_code = g_strndup (base_code, delimiter - base_code);
|
|
|
|
g_free (temp);
|
2013-07-20 13:51:13 +08:00
|
|
|
}
|
|
|
|
|
2024-08-15 06:02:32 +08:00
|
|
|
/* 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);
|
2024-08-14 21:48:37 +08:00
|
|
|
|
2024-08-15 06:02:32 +08:00
|
|
|
n_mo++;
|
2013-07-20 13:51:13 +08:00
|
|
|
}
|
2008-02-08 00:50:11 +08:00
|
|
|
|
2024-08-15 06:02:32 +08:00
|
|
|
n_locales++;
|
2024-08-14 21:48:37 +08:00
|
|
|
|
2024-08-15 06:02:32 +08:00
|
|
|
g_free (locale);
|
2024-08-14 21:48:37 +08:00
|
|
|
}
|
2024-08-15 06:02:32 +08:00
|
|
|
|
|
|
|
if (n_mo == 0)
|
2024-08-14 21:48:37 +08:00
|
|
|
{
|
2024-08-15 06:02:32 +08:00
|
|
|
g_set_error (error, G_IO_ERROR, 0,
|
|
|
|
"No \"%s\" files were found in %s in %d locales",
|
|
|
|
GETTEXT_PACKAGE ".mo", gimp_locale_directory (),
|
|
|
|
n_locales);
|
2024-08-14 21:48:37 +08:00
|
|
|
success = FALSE;
|
|
|
|
goto cleanup;
|
2013-07-20 13:51:13 +08:00
|
|
|
}
|
2008-02-12 07:10:58 +08:00
|
|
|
|
2013-07-20 13:51:13 +08:00
|
|
|
/* Parse ISO-639 file to get full list of language and their names. */
|
2024-08-14 21:48:37 +08:00
|
|
|
if (! parse_iso_codes (base_lang_list, error))
|
|
|
|
{
|
|
|
|
success = FALSE;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2008-02-08 21:50:34 +08:00
|
|
|
|
2013-07-20 13:51:13 +08:00
|
|
|
/* Generate the localized language names. */
|
|
|
|
g_hash_table_iter_init (&lang_iter, l10n_lang_list);
|
2024-08-15 19:22:48 +08:00
|
|
|
gimp_bind_text_domain ("iso_639_3", ISOCODES_LOCALEDIR);
|
2013-07-20 13:51:13 +08:00
|
|
|
while (g_hash_table_iter_next (&lang_iter, &key, NULL))
|
|
|
|
{
|
2013-07-28 22:12:17 +08:00
|
|
|
gchar *code = (gchar*) key;
|
|
|
|
gchar *localized_name = NULL;
|
|
|
|
gchar *english_name = NULL;
|
|
|
|
gchar *delimiter = NULL;
|
|
|
|
gchar *base_code = NULL;
|
|
|
|
|
|
|
|
delimiter = strchr (code, '_');
|
2013-07-20 13:51:13 +08:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2013-07-28 22:12:17 +08:00
|
|
|
english_name = (gchar*) (g_hash_table_lookup (base_lang_list, base_code));
|
2013-07-20 13:51:13 +08:00
|
|
|
|
|
|
|
if (english_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);
|
2024-08-15 18:07:12 +08:00
|
|
|
g_setenv ("LANG", code, TRUE);
|
2013-07-20 13:51:13 +08:00
|
|
|
setlocale (LC_ALL, "");
|
|
|
|
|
2024-08-13 23:03:56 +08:00
|
|
|
localized_name = g_strdup (dgettext ("iso_639_3", english_name));
|
2013-07-20 13:51:13 +08:00
|
|
|
|
|
|
|
/* 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);
|
2024-08-15 18:07:12 +08:00
|
|
|
g_setenv ("LANG", base_code, TRUE);
|
2013-07-20 13:51:13 +08:00
|
|
|
setlocale (LC_ALL, "");
|
|
|
|
|
2024-08-13 23:03:56 +08:00
|
|
|
localized_name = g_strdup (dgettext ("iso_639_3", english_name));
|
2013-07-20 13:51:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-28 22:12:17 +08:00
|
|
|
g_hash_table_replace (l10n_lang_list, g_strdup(code),
|
|
|
|
g_strdup_printf ("%s [%s]",
|
|
|
|
localized_name ?
|
|
|
|
localized_name : "???",
|
|
|
|
code));
|
|
|
|
g_free (localized_name);
|
2013-07-20 13:51:13 +08:00
|
|
|
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, "");
|
|
|
|
|
|
|
|
/* Go back to original localization. */
|
|
|
|
if (current_env)
|
|
|
|
{
|
|
|
|
g_setenv ("LANGUAGE", current_env, TRUE);
|
|
|
|
g_free (current_env);
|
|
|
|
}
|
|
|
|
else
|
2024-08-16 02:50:23 +08:00
|
|
|
{
|
|
|
|
g_unsetenv ("LANGUAGE");
|
|
|
|
}
|
2013-07-20 13:51:13 +08:00
|
|
|
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]"));
|
|
|
|
|
2024-08-14 21:48:37 +08:00
|
|
|
cleanup:
|
2013-07-20 13:51:13 +08:00
|
|
|
g_hash_table_destroy (base_lang_list);
|
tools: only list languages with part 1 and part 2 codes or with a localization.
Our GimpTranslationStore contains self-localized names of all languages
we support.
As for GimpLanguageStore, it contains all known languages with their
name in the current locale. When moving to ISO 639-3 list, we had all
possible language, included ancient ones, extinct ones, and so on. With
the iso-codes installation on my machine, this meant a struct with 7910
languages! When showing the Text tool options for the first time, GIMP's
UI is frozen for a few seconds because of this, while it constructs the
GimpLanguageEntry making use of the GimpLanguageStore.
By only listing part 1 and part 2 languages (as well as the rare
languages which are not in these list yet which we still support, i.e.
right now only 'ckb' (Central Kurdish), see #11626), the list lowers to
189 languages, which is still good and are the main languages or
language families AFAIU. And now the Text tool options are constructed
instantly.
Note that this is in fact even less than when we were just using
iso_639.xml (I counted 487 languages stored there), but I believe it to
be enough for the usage we have in the Text tool.
2024-08-10 17:05:32 +08:00
|
|
|
|
|
|
|
g_timer_stop (timer);
|
|
|
|
g_print ("%s: %f seconds\n", G_STRFUNC, g_timer_elapsed (timer, NULL));
|
|
|
|
g_timer_destroy (timer);
|
2024-08-15 06:02:32 +08:00
|
|
|
g_object_unref (linguas);
|
|
|
|
g_clear_object (&input);
|
|
|
|
g_clear_object (&dinput);
|
2024-08-14 21:48:37 +08:00
|
|
|
|
|
|
|
return success;
|
2009-12-31 06:55:26 +08:00
|
|
|
}
|
|
|
|
|
2024-08-10 08:02:49 +08:00
|
|
|
static void
|
2013-07-20 13:51:13 +08:00
|
|
|
gimp_language_store_parser_clean (void)
|
2009-12-31 06:55:26 +08:00
|
|
|
{
|
2013-07-20 13:51:13 +08:00
|
|
|
g_hash_table_destroy (l10n_lang_list);
|
|
|
|
g_hash_table_destroy (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)
|
|
|
|
{
|
2014-07-29 21:55:12 +08:00
|
|
|
gboolean success = TRUE;
|
|
|
|
|
2009-12-31 06:55:26 +08:00
|
|
|
#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 */
|
|
|
|
};
|
|
|
|
|
2014-07-29 21:55:12 +08:00
|
|
|
GimpXmlParser *xml_parser;
|
|
|
|
GFile *file;
|
|
|
|
IsoCodesParser parser = { 0, };
|
2009-12-31 06:55:26 +08:00
|
|
|
|
|
|
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
|
|
|
|
|
|
|
iso_codes_parser_init ();
|
|
|
|
|
2013-07-20 13:51:13 +08:00
|
|
|
parser.base_lang_list = g_hash_table_ref (base_lang_list);
|
2008-02-08 00:50:11 +08:00
|
|
|
|
|
|
|
xml_parser = gimp_xml_parser_new (&markup_parser, &parser);
|
|
|
|
|
2019-02-03 00:07:03 +08:00
|
|
|
file = g_file_new_for_path (ISO_CODES_LOCATION G_DIR_SEPARATOR_S
|
2024-05-31 03:51:41 +08:00
|
|
|
"iso_639_3.xml");
|
2008-02-08 00:50:11 +08:00
|
|
|
|
2014-07-29 21:55:12 +08:00
|
|
|
success = gimp_xml_parser_parse_gfile (xml_parser, file, error);
|
2024-08-14 21:48:37 +08:00
|
|
|
if (*error)
|
|
|
|
{
|
|
|
|
g_prefix_error (error, "%s: error parsing '%s': ",
|
|
|
|
G_STRFUNC, g_file_peek_path (file));
|
|
|
|
success = FALSE;
|
|
|
|
}
|
|
|
|
else if (g_hash_table_size (all_lang_list) == 0)
|
2017-06-12 07:17:17 +08:00
|
|
|
{
|
2024-08-14 21:48:37 +08:00
|
|
|
g_set_error (error, G_IO_ERROR, 0,
|
|
|
|
"No language entries found in %s.",
|
|
|
|
g_file_peek_path (file));
|
|
|
|
success = FALSE;
|
2017-06-12 07:17:17 +08:00
|
|
|
}
|
2008-02-08 00:50:11 +08:00
|
|
|
|
2014-07-29 21:55:12 +08:00
|
|
|
g_object_unref (file);
|
2008-02-08 21:50:34 +08:00
|
|
|
|
|
|
|
gimp_xml_parser_free (xml_parser);
|
2013-07-20 13:51:13 +08:00
|
|
|
g_hash_table_unref (parser.base_lang_list);
|
|
|
|
|
2015-01-10 07:03:04 +08:00
|
|
|
#endif /* HAVE_ISO_CODES */
|
2008-02-08 20:28:36 +08:00
|
|
|
|
|
|
|
return success;
|
2013-07-20 13:51:13 +08:00
|
|
|
}
|
|
|
|
|
2015-01-10 07:03:04 +08:00
|
|
|
#ifdef HAVE_ISO_CODES
|
2013-07-20 13:51:13 +08:00
|
|
|
static void
|
|
|
|
iso_codes_parser_init (void)
|
|
|
|
{
|
|
|
|
static gboolean initialized = FALSE;
|
|
|
|
|
|
|
|
if (initialized)
|
|
|
|
return;
|
|
|
|
|
|
|
|
#ifdef G_OS_WIN32
|
|
|
|
/* on Win32, assume iso-codes is installed in the same location as GIMP */
|
2024-05-31 03:51:41 +08:00
|
|
|
gimp_bind_text_domain ("iso_639_3", gimp_locale_directory ());
|
2013-07-20 13:51:13 +08:00
|
|
|
#else
|
2024-05-31 03:51:41 +08:00
|
|
|
gimp_bind_text_domain ("iso_639_3", ISO_CODES_LOCALEDIR);
|
2008-02-08 00:50:11 +08:00
|
|
|
#endif
|
|
|
|
|
2024-05-31 03:51:41 +08:00
|
|
|
bind_textdomain_codeset ("iso_639_3", "UTF-8");
|
2013-07-20 13:51:13 +08:00
|
|
|
|
|
|
|
initialized = TRUE;
|
2008-02-08 00:50:11 +08:00
|
|
|
}
|
|
|
|
|
2008-02-08 20:28:36 +08:00
|
|
|
static void
|
|
|
|
iso_codes_parser_entry (IsoCodesParser *parser,
|
|
|
|
const gchar **names,
|
|
|
|
const gchar **values)
|
|
|
|
{
|
tools: only list languages with part 1 and part 2 codes or with a localization.
Our GimpTranslationStore contains self-localized names of all languages
we support.
As for GimpLanguageStore, it contains all known languages with their
name in the current locale. When moving to ISO 639-3 list, we had all
possible language, included ancient ones, extinct ones, and so on. With
the iso-codes installation on my machine, this meant a struct with 7910
languages! When showing the Text tool options for the first time, GIMP's
UI is frozen for a few seconds because of this, while it constructs the
GimpLanguageEntry making use of the GimpLanguageStore.
By only listing part 1 and part 2 languages (as well as the rare
languages which are not in these list yet which we still support, i.e.
right now only 'ckb' (Central Kurdish), see #11626), the list lowers to
189 languages, which is still good and are the main languages or
language families AFAIU. And now the Text tool options are constructed
instantly.
Note that this is in fact even less than when we were just using
iso_639.xml (I counted 487 languages stored there), but I believe it to
be enough for the usage we have in the Text tool.
2024-08-10 17:05:32 +08:00
|
|
|
const gchar *lang = NULL;
|
|
|
|
const gchar *code = NULL;
|
|
|
|
gboolean has_part12 = FALSE;
|
2008-02-08 20:28:36 +08:00
|
|
|
|
|
|
|
while (*names && *values)
|
|
|
|
{
|
|
|
|
if (strcmp (*names, "name") == 0)
|
tools: only list languages with part 1 and part 2 codes or with a localization.
Our GimpTranslationStore contains self-localized names of all languages
we support.
As for GimpLanguageStore, it contains all known languages with their
name in the current locale. When moving to ISO 639-3 list, we had all
possible language, included ancient ones, extinct ones, and so on. With
the iso-codes installation on my machine, this meant a struct with 7910
languages! When showing the Text tool options for the first time, GIMP's
UI is frozen for a few seconds because of this, while it constructs the
GimpLanguageEntry making use of the GimpLanguageStore.
By only listing part 1 and part 2 languages (as well as the rare
languages which are not in these list yet which we still support, i.e.
right now only 'ckb' (Central Kurdish), see #11626), the list lowers to
189 languages, which is still good and are the main languages or
language families AFAIU. And now the Text tool options are constructed
instantly.
Note that this is in fact even less than when we were just using
iso_639.xml (I counted 487 languages stored there), but I believe it to
be enough for the usage we have in the Text tool.
2024-08-10 17:05:32 +08:00
|
|
|
{
|
|
|
|
lang = *values;
|
|
|
|
}
|
2024-05-31 03:51:41 +08:00
|
|
|
else if (strcmp (*names, "part1_code") == 0)
|
2013-07-20 13:51:13 +08:00
|
|
|
/* 2-letter ISO 639-1 codes have priority.
|
|
|
|
* But some languages have no 2-letter code. Ex: Asturian (ast).
|
|
|
|
*/
|
tools: only list languages with part 1 and part 2 codes or with a localization.
Our GimpTranslationStore contains self-localized names of all languages
we support.
As for GimpLanguageStore, it contains all known languages with their
name in the current locale. When moving to ISO 639-3 list, we had all
possible language, included ancient ones, extinct ones, and so on. With
the iso-codes installation on my machine, this meant a struct with 7910
languages! When showing the Text tool options for the first time, GIMP's
UI is frozen for a few seconds because of this, while it constructs the
GimpLanguageEntry making use of the GimpLanguageStore.
By only listing part 1 and part 2 languages (as well as the rare
languages which are not in these list yet which we still support, i.e.
right now only 'ckb' (Central Kurdish), see #11626), the list lowers to
189 languages, which is still good and are the main languages or
language families AFAIU. And now the Text tool options are constructed
instantly.
Note that this is in fact even less than when we were just using
iso_639.xml (I counted 487 languages stored there), but I believe it to
be enough for the usage we have in the Text tool.
2024-08-10 17:05:32 +08:00
|
|
|
{
|
|
|
|
code = *values;
|
|
|
|
has_part12 = TRUE;
|
|
|
|
}
|
2024-05-31 03:51:41 +08:00
|
|
|
else if (strcmp (*names, "part2_code") == 0 && code == NULL)
|
tools: only list languages with part 1 and part 2 codes or with a localization.
Our GimpTranslationStore contains self-localized names of all languages
we support.
As for GimpLanguageStore, it contains all known languages with their
name in the current locale. When moving to ISO 639-3 list, we had all
possible language, included ancient ones, extinct ones, and so on. With
the iso-codes installation on my machine, this meant a struct with 7910
languages! When showing the Text tool options for the first time, GIMP's
UI is frozen for a few seconds because of this, while it constructs the
GimpLanguageEntry making use of the GimpLanguageStore.
By only listing part 1 and part 2 languages (as well as the rare
languages which are not in these list yet which we still support, i.e.
right now only 'ckb' (Central Kurdish), see #11626), the list lowers to
189 languages, which is still good and are the main languages or
language families AFAIU. And now the Text tool options are constructed
instantly.
Note that this is in fact even less than when we were just using
iso_639.xml (I counted 487 languages stored there), but I believe it to
be enough for the usage we have in the Text tool.
2024-08-10 17:05:32 +08:00
|
|
|
{
|
|
|
|
code = *values;
|
|
|
|
has_part12 = TRUE;
|
|
|
|
}
|
2024-05-31 03:51:41 +08:00
|
|
|
else if (strcmp (*names, "id") == 0 && code == NULL)
|
tools: only list languages with part 1 and part 2 codes or with a localization.
Our GimpTranslationStore contains self-localized names of all languages
we support.
As for GimpLanguageStore, it contains all known languages with their
name in the current locale. When moving to ISO 639-3 list, we had all
possible language, included ancient ones, extinct ones, and so on. With
the iso-codes installation on my machine, this meant a struct with 7910
languages! When showing the Text tool options for the first time, GIMP's
UI is frozen for a few seconds because of this, while it constructs the
GimpLanguageEntry making use of the GimpLanguageStore.
By only listing part 1 and part 2 languages (as well as the rare
languages which are not in these list yet which we still support, i.e.
right now only 'ckb' (Central Kurdish), see #11626), the list lowers to
189 languages, which is still good and are the main languages or
language families AFAIU. And now the Text tool options are constructed
instantly.
Note that this is in fact even less than when we were just using
iso_639.xml (I counted 487 languages stored there), but I believe it to
be enough for the usage we have in the Text tool.
2024-08-10 17:05:32 +08:00
|
|
|
{
|
|
|
|
code = *values;
|
|
|
|
}
|
2008-02-08 20:28:36 +08:00
|
|
|
|
|
|
|
names++;
|
|
|
|
values++;
|
|
|
|
}
|
2008-02-08 21:50:34 +08:00
|
|
|
|
|
|
|
if (lang && *lang && code && *code)
|
|
|
|
{
|
2024-08-10 20:48:30 +08:00
|
|
|
gboolean save_anyway = FALSE;
|
2008-02-08 21:50:34 +08:00
|
|
|
|
2013-07-20 13:51:13 +08:00
|
|
|
/* If the language is in our base table, we save its standard English name. */
|
|
|
|
if (g_hash_table_contains (parser->base_lang_list, code))
|
tools: only list languages with part 1 and part 2 codes or with a localization.
Our GimpTranslationStore contains self-localized names of all languages
we support.
As for GimpLanguageStore, it contains all known languages with their
name in the current locale. When moving to ISO 639-3 list, we had all
possible language, included ancient ones, extinct ones, and so on. With
the iso-codes installation on my machine, this meant a struct with 7910
languages! When showing the Text tool options for the first time, GIMP's
UI is frozen for a few seconds because of this, while it constructs the
GimpLanguageEntry making use of the GimpLanguageStore.
By only listing part 1 and part 2 languages (as well as the rare
languages which are not in these list yet which we still support, i.e.
right now only 'ckb' (Central Kurdish), see #11626), the list lowers to
189 languages, which is still good and are the main languages or
language families AFAIU. And now the Text tool options are constructed
instantly.
Note that this is in fact even less than when we were just using
iso_639.xml (I counted 487 languages stored there), but I believe it to
be enough for the usage we have in the Text tool.
2024-08-10 17:05:32 +08:00
|
|
|
{
|
|
|
|
g_hash_table_replace (parser->base_lang_list, g_strdup (code), g_strdup (lang));
|
|
|
|
save_anyway = TRUE;
|
|
|
|
}
|
2008-02-08 21:50:34 +08:00
|
|
|
|
2024-08-10 20:48:30 +08:00
|
|
|
/* In any case, we save the name in US English for all lang with
|
|
|
|
* part 1 or part 2 code, or for the few language with no part 1|2
|
|
|
|
* code but for which we have a localization.
|
tools: only list languages with part 1 and part 2 codes or with a localization.
Our GimpTranslationStore contains self-localized names of all languages
we support.
As for GimpLanguageStore, it contains all known languages with their
name in the current locale. When moving to ISO 639-3 list, we had all
possible language, included ancient ones, extinct ones, and so on. With
the iso-codes installation on my machine, this meant a struct with 7910
languages! When showing the Text tool options for the first time, GIMP's
UI is frozen for a few seconds because of this, while it constructs the
GimpLanguageEntry making use of the GimpLanguageStore.
By only listing part 1 and part 2 languages (as well as the rare
languages which are not in these list yet which we still support, i.e.
right now only 'ckb' (Central Kurdish), see #11626), the list lowers to
189 languages, which is still good and are the main languages or
language families AFAIU. And now the Text tool options are constructed
instantly.
Note that this is in fact even less than when we were just using
iso_639.xml (I counted 487 languages stored there), but I believe it to
be enough for the usage we have in the Text tool.
2024-08-10 17:05:32 +08:00
|
|
|
*/
|
|
|
|
if (has_part12 || save_anyway)
|
2024-08-10 20:48:30 +08:00
|
|
|
g_hash_table_insert (all_lang_list, g_strdup (code), g_strdup (lang));
|
2008-02-08 21:50:34 +08:00
|
|
|
}
|
2008-02-08 20:28:36 +08:00
|
|
|
}
|
|
|
|
|
2008-02-08 00:50:11 +08:00
|
|
|
static void
|
|
|
|
iso_codes_parser_start_element (GMarkupParseContext *context,
|
|
|
|
const gchar *element_name,
|
|
|
|
const gchar **attribute_names,
|
|
|
|
const gchar **attribute_values,
|
|
|
|
gpointer user_data,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
IsoCodesParser *parser = user_data;
|
|
|
|
|
|
|
|
switch (parser->state)
|
|
|
|
{
|
2008-02-08 20:28:36 +08:00
|
|
|
case ISO_CODES_START:
|
2024-05-31 03:51:41 +08:00
|
|
|
if (strcmp (element_name, "iso_639_3_entries") == 0)
|
2008-02-08 20:28:36 +08:00
|
|
|
{
|
|
|
|
parser->state = ISO_CODES_IN_ENTRIES;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ISO_CODES_IN_ENTRIES:
|
2024-05-31 03:51:41 +08:00
|
|
|
if (strcmp (element_name, "iso_639_3_entry") == 0)
|
2008-02-08 20:28:36 +08:00
|
|
|
{
|
|
|
|
parser->state = ISO_CODES_IN_ENTRY;
|
|
|
|
iso_codes_parser_entry (parser, attribute_names, attribute_values);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ISO_CODES_IN_ENTRY:
|
|
|
|
case ISO_CODES_IN_UNKNOWN:
|
2008-02-08 00:50:11 +08:00
|
|
|
iso_codes_parser_start_unknown (parser);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
iso_codes_parser_end_element (GMarkupParseContext *context,
|
|
|
|
const gchar *element_name,
|
|
|
|
gpointer user_data,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
IsoCodesParser *parser = user_data;
|
|
|
|
|
|
|
|
switch (parser->state)
|
|
|
|
{
|
2008-02-08 20:28:36 +08:00
|
|
|
case ISO_CODES_START:
|
|
|
|
g_warning ("%s: shouldn't get here", G_STRLOC);
|
2008-02-08 00:50:11 +08:00
|
|
|
break;
|
|
|
|
|
2008-02-08 20:28:36 +08:00
|
|
|
case ISO_CODES_IN_ENTRIES:
|
|
|
|
parser->state = ISO_CODES_START;
|
|
|
|
break;
|
2008-02-08 00:50:11 +08:00
|
|
|
|
2008-02-08 20:28:36 +08:00
|
|
|
case ISO_CODES_IN_ENTRY:
|
|
|
|
parser->state = ISO_CODES_IN_ENTRIES;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ISO_CODES_IN_UNKNOWN:
|
|
|
|
iso_codes_parser_end_unknown (parser);
|
2008-02-08 00:50:11 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
iso_codes_parser_start_unknown (IsoCodesParser *parser)
|
|
|
|
{
|
|
|
|
if (parser->unknown_depth == 0)
|
|
|
|
parser->last_known_state = parser->state;
|
|
|
|
|
|
|
|
parser->state = ISO_CODES_IN_UNKNOWN;
|
|
|
|
parser->unknown_depth++;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
iso_codes_parser_end_unknown (IsoCodesParser *parser)
|
|
|
|
{
|
2018-02-12 05:23:10 +08:00
|
|
|
gimp_assert (parser->unknown_depth > 0 &&
|
|
|
|
parser->state == ISO_CODES_IN_UNKNOWN);
|
2008-02-08 00:50:11 +08:00
|
|
|
|
|
|
|
parser->unknown_depth--;
|
|
|
|
|
|
|
|
if (parser->unknown_depth == 0)
|
|
|
|
parser->state = parser->last_known_state;
|
|
|
|
}
|
2015-01-10 07:03:04 +08:00
|
|
|
#endif /* HAVE_ISO_CODES */
|