[evolution] I#680 - Change how supported locales for composer attribution language are detected



commit d9b67c30aae4893fc15c60dfd3a073391b7f1e3d
Author: Milan Crha <mcrha redhat com>
Date:   Wed Nov 6 14:31:54 2019 +0100

    I#680 - Change how supported locales for composer attribution language are detected
    
    Closes https://gitlab.gnome.org/GNOME/evolution/issues/680

 src/e-util/CMakeLists.txt                |  16 ++++
 src/e-util/e-misc-utils.c                |  55 +++++++++++++
 src/e-util/e-misc-utils.h                |   9 +++
 src/e-util/e-supported-locales-private.h | 126 +++++++++++++++++++++++++++++
 src/mail/em-composer-utils.c             | 131 +++++++++----------------------
 src/shell/main.c                         |   3 +
 6 files changed, 246 insertions(+), 94 deletions(-)
---
diff --git a/src/e-util/CMakeLists.txt b/src/e-util/CMakeLists.txt
index b8de2be054..1cfeab1f97 100644
--- a/src/e-util/CMakeLists.txt
+++ b/src/e-util/CMakeLists.txt
@@ -224,6 +224,7 @@ set(SOURCES
        e-spell-text-view.c
        e-spinner.c
        e-stock-request.c
+       e-supported-locales-private.h
        e-table-click-to-add.c
        e-table-col.c
        e-table-column-selector.c
@@ -824,3 +825,18 @@ add_private_program(test-html-editor-units
        test-html-editor-units-utils.c
 )
 add_dependencies(test-html-editor-units evolutiontestsettings)
+
+# verify e-supported-locales-private.h contains all locales from /po directory
+if(ENABLE_MAINTAINER_MODE)
+       set(priv_file ${CMAKE_CURRENT_SOURCE_DIR}/e-supported-locales-private.h)
+       file(GLOB po_files ${GETTEXT_PO_DIR}/*.po)
+       file(READ ${priv_file} supported_locales)
+
+       foreach(file IN LISTS po_files)
+               get_filename_component(lang ${file} NAME_WE)
+               string(FIND "${supported_locales}" "\"${lang}\"" found)
+               if(found LESS 0)
+                       message(SEND_ERROR "Localization '${lang}' missing in ${priv_file}, add it with 
corresponding locale string")
+               endif(found LESS 0)
+       endforeach(file)
+endif(ENABLE_MAINTAINER_MODE)
diff --git a/src/e-util/e-misc-utils.c b/src/e-util/e-misc-utils.c
index 679d118d66..3b3f27e016 100644
--- a/src/e-util/e-misc-utils.c
+++ b/src/e-util/e-misc-utils.c
@@ -67,6 +67,7 @@
 #include "e-spell-checker.h"
 #include "e-util-private.h"
 #include "e-xml-utils.h"
+#include "e-supported-locales-private.h"
 
 typedef struct _WindowData WindowData;
 
@@ -4606,6 +4607,15 @@ e_util_get_language_info (const gchar *language_tag,
        }
 
  exit:
+       if (out_language_name && *out_language_name) {
+               gchar *ptr;
+
+               /* When the language name has ';' then strip the string at it */
+               ptr = strchr (*out_language_name, ';');
+               if (ptr)
+                       *ptr = '\0';
+       }
+
        if (out_country_name && *out_country_name) {
                gchar *ptr;
 
@@ -4744,3 +4754,48 @@ e_util_markup_append_escaped (GString *buffer,
 
        g_free (escaped);
 }
+
+void
+e_util_enum_supported_locales (void)
+{
+       GString *locale;
+       gchar *previous_locale;
+       gint ii, category = LC_ALL;
+
+       #if defined(LC_MESSAGES)
+       category = LC_MESSAGES;
+       #endif
+
+       previous_locale = g_strdup (setlocale (category, NULL));
+
+       locale = g_string_sized_new (32);
+
+       for (ii = 0; e_supported_locales[ii].code; ii++) {
+               gchar *catalog_filename;
+
+               catalog_filename = g_build_filename (EVOLUTION_LOCALEDIR, e_supported_locales[ii].code, 
"LC_MESSAGES", GETTEXT_PACKAGE ".mo", NULL);
+
+               if (catalog_filename && g_file_test (catalog_filename, G_FILE_TEST_EXISTS)) {
+                       g_string_printf (locale, "%s.utf8", e_supported_locales[ii].locale);
+
+                       if (!setlocale (category, locale->str)) {
+                               e_supported_locales[ii].locale = NULL;
+                       }
+               } else {
+                       e_supported_locales[ii].locale = NULL;
+               }
+
+               g_free (catalog_filename);
+       }
+
+       setlocale (category, previous_locale);
+
+       g_string_free (locale, TRUE);
+       g_free (previous_locale);
+}
+
+const ESupportedLocales *
+e_util_get_supported_locales (void)
+{
+       return e_supported_locales;
+}
diff --git a/src/e-util/e-misc-utils.h b/src/e-util/e-misc-utils.h
index d91b6708da..9b1efc389b 100644
--- a/src/e-util/e-misc-utils.h
+++ b/src/e-util/e-misc-utils.h
@@ -364,6 +364,15 @@ void               e_util_markup_append_escaped    (GString *buffer,
                                                 const gchar *format,
                                                 ...) G_GNUC_PRINTF (2, 3);
 
+typedef struct _ESupportedLocales {
+       const gchar *code;      /* like 'en' */
+       const gchar *locale;    /* like 'en_US' */
+} ESupportedLocales;
+
+void           e_util_enum_supported_locales   (void);
+const ESupportedLocales *
+               e_util_get_supported_locales    (void);
+
 G_END_DECLS
 
 #endif /* E_MISC_UTILS_H */
diff --git a/src/e-util/e-supported-locales-private.h b/src/e-util/e-supported-locales-private.h
new file mode 100644
index 0000000000..bd55676762
--- /dev/null
+++ b/src/e-util/e-supported-locales-private.h
@@ -0,0 +1,126 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * 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 Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef E_SUPPORTED_LOCALES_PRIVATE_H
+#define E_SUPPORTED_LOCALES_PRIVATE_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+/* This should be included only in e-misc-utils.c and after e-misc-utils.h */
+
+/* An array of known supported translations with corresponding locale codes */
+
+static ESupportedLocales e_supported_locales[] = {
+       { "af", "af_ZA" },
+       { "am", "am_ET" },
+       { "an", "an_ES" },
+       { "ar", "ar_IN" },
+       { "as", "as_IN" },
+       { "ast", "ast_ES" },
+       { "az", "az_AZ" },
+       { "be", "be_BY" },
+       { "be@latin", "be_BY@latin" },
+       { "bg", "bg_BG" },
+       { "bn", "bn_IN" },
+       { "br", "br_FR" },
+       { "bs", "bs_BA" },
+       { "ca", "ca_ES" },
+       { "ca@valencia", "ca_ES@valencia" },
+       { "cs", "cs_CZ" },
+       { "cy", "cy_GB" },
+       { "da", "da_DK" },
+       { "de", "de_DE" },
+       { "dz", "dz_BT" },
+       { "el", "el_GR" },
+       { "en", "en_US" },
+       { "en_AU", "en_AU" },
+       { "en_CA", "en_CA" },
+       { "en_GB", "en_GB" },
+       { "en@shaw", "en_US@shaw" },
+       { "eo", "eo_EO" },
+       { "es", "es_ES" },
+       { "et", "et_EE" },
+       { "eu", "eu_ES" },
+       { "fa", "fa_IR" },
+       { "fi", "fi_FI" },
+       { "fr", "fr_FR" },
+       { "fur", "fur_IT" },
+       { "ga", "ga_IE" },
+       { "gl", "gl_ES" },
+       { "gu", "gu_IN" },
+       { "he", "he_IL" },
+       { "hi", "hi_IN" },
+       { "hr", "hr_HR" },
+       { "hu", "hu_HU" },
+       { "id", "id_ID" },
+       { "is", "is_IS" },
+       { "it", "it_IT" },
+       { "ja", "ja_JP" },
+       { "ka", "ka_GE" },
+       { "kk", "kk_KZ" },
+       { "kn", "kn_IN" },
+       { "ko", "ko_KR" },
+       { "ku", "ku_TR" },
+       { "lt", "lt_LT" },
+       { "lv", "lv_LV" },
+       { "mai", "mai_IN" },
+       { "mk", "mk_MK" },
+       { "ml", "ml_IN" },
+       { "mn", "mn_MN" },
+       { "mr", "mr_IN" },
+       { "ms", "ms_MY" },
+       { "nb", "nb_NO" },
+       { "nds", "nds_NL" },
+       { "ne", "ne_NP" },
+       { "nl", "nl_NL" },
+       { "nn", "nn_NO" },
+       { "oc", "oc_FR" },
+       { "or", "or_IN" },
+       { "pa", "pa_IN" },
+       { "pl", "pl_PL" },
+       { "ps", "ps_AF" },
+       { "pt", "pt_PT" },
+       { "pt_BR", "pt_BR" },
+       { "ro", "ro_RO" },
+       { "ru", "ru_RU" },
+       { "rw", "rw_RW" },
+       { "si", "si_LK" },
+       { "sk", "sk_SK" },
+       { "sl", "sl_SI" },
+       { "sq", "sq_AL" },
+       { "sr", "sr_RS" },
+       { "sr@latin", "sr_RS@latin" },
+       { "sv", "sv_FI" },
+       { "ta", "ta_IN" },
+       { "te", "te_IN" },
+       { "tg", "tg_TJ" },
+       { "th", "th_TH" },
+       { "tr", "tr_TR" },
+       { "ug", "ug_CN" },
+       { "uk", "uk_UA" },
+       { "vi", "vi_VN" },
+       { "wa", "wa_BE" },
+       { "xh", "xh_ZA" },
+       { "zh_CN", "zh_CN" },
+       { "zh_HK", "zh_HK" },
+       { "zh_TW", "zh_TW" },
+       { NULL, NULL }
+};
+
+G_END_DECLS
+
+#endif /* E_SUPPORTED_LOCALES_PRIVATE_H */
diff --git a/src/mail/em-composer-utils.c b/src/mail/em-composer-utils.c
index 24f0f120c5..fb4b85b570 100644
--- a/src/mail/em-composer-utils.c
+++ b/src/mail/em-composer-utils.c
@@ -4847,124 +4847,67 @@ em_utils_apply_send_account_override_to_composer (EMsgComposer *composer,
        g_free (alias_address);
 }
 
-static GHashTable * /* gchar *lcmessages ~> gchar *localeID */
-em_enum_system_locales (void)
+void
+em_utils_add_installed_languages (GtkComboBoxText *combo)
 {
+       const ESupportedLocales *supported_locales;
        GHashTable *locales;
+       GList *langs = NULL, *link;
+       gboolean has_en_us = FALSE;
+       gint ii, n_langs = 0;
 
-#ifdef G_OS_WIN32
-       /* Do not know how to test it right now (2018), the build
-          on Windows is blocked by WebKitGTK+ anyway. */
-       #warning See gtk/gtkmain.c and its usage of EnumSystemLocales()
-#else
-       GDir *dir;
-       const gchar *dirname;
-
-       locales = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
-
-       dir = g_dir_open ("/usr/lib/locale", 0, NULL);
-       if (dir) {
-               while (dirname = g_dir_read_name (dir), dirname) {
-                       gchar *fullname, *ident = NULL, *ptr;
-
-                       if (g_str_equal (dirname, ".") || g_str_equal (dirname, "..") || !strchr (dirname, 
'_'))
-                               continue;
-
-                       fullname = g_strdup (dirname);
-                       ptr = strrchr (fullname, '.');
-                       if (ptr)
-                               *ptr = '\0';
-
-                       if (!g_hash_table_contains (locales, fullname)) {
-                               gchar *at;
+       g_return_if_fail (GTK_IS_COMBO_BOX_TEXT (combo));
 
-                               g_hash_table_insert (locales, g_strdup (fullname), g_strdup (fullname));
+       supported_locales = e_util_get_supported_locales ();
+       locales = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 
-                               ident = g_strdup (fullname);
-                               at = strchr (ident, '@');
-                               if (at) {
-                                       *at = 0;
-                                       g_hash_table_insert (locales, g_strdup (ident), g_strdup (fullname));
-                               }
+       for (ii = 0; supported_locales[ii].code; ii++) {
+               const gchar *locale = supported_locales[ii].locale;
 
-                               ptr = strchr (ident, '_');
-                               if (ptr) {
-                                       *ptr = '\0';
+               if (locale) {
+                       gchar *name;
 
-                                       g_hash_table_insert (locales, g_strdup (ident), g_strdup (fullname));
+                       name = e_util_get_language_name (locale);
 
-                                       if (at)
-                                               g_hash_table_insert (locales, g_strconcat (ident, "@", at + 
1, NULL), g_strdup (fullname));
-                               }
+                       if (name && *name) {
+                               g_hash_table_insert (locales, name, (gpointer) locale);
+                       } else {
+                               g_free (name);
+                               g_hash_table_insert (locales, g_strdup (locale), (gpointer) locale);
                        }
 
-                       g_free (fullname);
-                       g_free (ident);
+                       has_en_us = has_en_us || g_strcmp0 (locale, "en_US") == 0;
                }
        }
 
-       g_dir_close (dir);
-#endif
-
-       return locales;
-}
-
-void
-em_utils_add_installed_languages (GtkComboBoxText *combo)
-{
-       GDir *dir;
-       GSList *langs = NULL, *link;
-       const gchar *dirname;
-       gint n_langs = 0;
-       GHashTable *system_locales;
-
-       g_return_if_fail (GTK_IS_COMBO_BOX_TEXT (combo));
-
-       dir = g_dir_open (EVOLUTION_LOCALEDIR, 0, NULL);
-       if (!dir)
-               return;
-
-       system_locales = em_enum_system_locales ();
-
-       while (dirname = g_dir_read_name (dir), dirname) {
-               gchar *filename;
+       if (!has_en_us) {
+               const gchar *locale = "C";
+               gchar *name = e_util_get_language_name ("en_US");
 
-               if (g_str_equal (dirname, ".") || g_str_equal (dirname, ".."))
-                       continue;
-
-               filename = g_build_filename (EVOLUTION_LOCALEDIR, dirname, "LC_MESSAGES", GETTEXT_PACKAGE 
".mo", NULL);
-               if (filename && g_file_test (filename, G_FILE_TEST_EXISTS)) {
-                       gchar *locale_name;
-
-                       locale_name = g_hash_table_lookup (system_locales, dirname);
-                       if (locale_name)
-                               langs = g_slist_prepend (langs, g_strdup (locale_name));
+               if (name && *name) {
+                       g_hash_table_insert (locales, name, (gpointer) locale);
+               } else {
+                       g_free (name);
+                       g_hash_table_insert (locales, g_strdup ("en_US"), (gpointer) locale);
                }
-
-               g_free (filename);
        }
 
-       g_hash_table_destroy (system_locales);
-       g_dir_close (dir);
-
-       langs = g_slist_sort (langs, (GCompareFunc) g_strcmp0);
+       langs = g_hash_table_get_keys (locales);
+       langs = g_list_sort (langs, (GCompareFunc) g_utf8_collate);
 
-       for (link = langs; link; link = g_slist_next (link)) {
-               const gchar *lang = link->data;
+       for (link = langs; link; link = g_list_next (link)) {
+               const gchar *lang_name = link->data;
 
-               if (lang) {
-                       gchar *lang_name;
+               if (lang_name) {
+                       const gchar *locale = g_hash_table_lookup (locales, lang_name);
 
-                       lang_name = e_util_get_language_name (lang);
-
-                       gtk_combo_box_text_append (combo, lang, lang_name && *lang_name ? lang_name : lang);
+                       gtk_combo_box_text_append (combo, locale, lang_name);
                        n_langs++;
-
-                       g_free (lang_name);
                }
        }
 
-       g_slist_free_full (langs, g_free);
+       g_hash_table_destroy (locales);
+       g_list_free (langs);
 
        if (n_langs > 10)
                gtk_combo_box_set_wrap_width (GTK_COMBO_BOX (combo), 5);
diff --git a/src/shell/main.c b/src/shell/main.c
index 6dc5b8b8ae..5d089225ca 100644
--- a/src/shell/main.c
+++ b/src/shell/main.c
@@ -475,6 +475,9 @@ main (gint argc,
                return 0;
        }
 
+       /* Pre-cache list of supported locales */
+       e_util_enum_supported_locales ();
+
        /* Initialize timezone specific global variables */
        tzset ();
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]