[evolution] Bug 228772 - Allow to specify a default language for a given identity



commit 65f7ba867d3f367a46a1a7a8d766a98190eeb1d0
Author: Milan Crha <mcrha redhat com>
Date:   Mon Oct 8 19:05:54 2018 +0200

    Bug 228772 - Allow to specify a default language for a given identity
    
    Closes https://bugzilla.gnome.org/show_bug.cgi?id=228772

 data/org.gnome.evolution.mail.gschema.xml.in       |   4 +
 src/addressbook/gui/contact-editor/test-editor.c   |   2 +-
 src/composer/e-composer-private.c                  | 103 +++++++
 src/composer/e-composer-private.h                  |   2 +
 src/e-util/e-html-editor-actions.c                 |  38 +++
 src/e-util/e-html-editor-private.h                 |   3 +
 src/e-util/e-html-editor.c                         |   1 +
 src/e-util/e-misc-utils.c                          | 303 ++++++++++++++++++++
 src/e-util/e-misc-utils.h                          |   2 +
 src/e-util/e-spell-checker.c                       |   6 +-
 src/e-util/e-spell-dictionary.c                    | 252 +---------------
 src/e-util/evolution-source-viewer.c               |   2 +-
 src/e-util/test-accounts-window.c                  |   2 +-
 src/e-util/test-calendar.c                         |   2 +-
 src/e-util/test-category-completion.c              |   2 +-
 src/e-util/test-contact-store.c                    |   2 +-
 src/e-util/test-dateedit.c                         |   2 +-
 src/e-util/test-html-editor-units.c                |   3 +-
 src/e-util/test-html-editor.c                      |   3 +-
 src/e-util/test-mail-signatures.c                  |   2 +-
 src/e-util/test-name-selector.c                    |   2 +-
 src/e-util/test-preferences-window.c               |   2 +-
 src/e-util/test-proxy-preferences.c                |   2 +-
 src/e-util/test-source-combo-box.c                 |   2 +-
 src/e-util/test-source-config.c                    |   2 +-
 src/e-util/test-source-selector.c                  |   2 +-
 src/e-util/test-tree-view-frame.c                  |   2 +-
 src/mail/CMakeLists.txt                            |   1 +
 src/mail/e-mail-config-composing-page.c            |  64 ++++-
 src/mail/em-composer-utils.c                       | 317 ++++++++++++++++++---
 src/mail/em-composer-utils.h                       |   9 +-
 src/mail/mail-config.ui                            |  66 ++++-
 src/modules/backup-restore/evolution-backup-tool.c |   2 +-
 src/modules/mail/em-composer-prefs.c               |  13 +
 .../attachment-reminder/attachment-reminder.c      |  11 +-
 src/shell/main.c                                   |   4 +-
 36 files changed, 888 insertions(+), 349 deletions(-)
---
diff --git a/data/org.gnome.evolution.mail.gschema.xml.in b/data/org.gnome.evolution.mail.gschema.xml.in
index c1c4788aad..44c9ba7825 100644
--- a/data/org.gnome.evolution.mail.gschema.xml.in
+++ b/data/org.gnome.evolution.mail.gschema.xml.in
@@ -476,6 +476,10 @@
       <default>'quoted'</default>
       <_summary>Default reply style</_summary>
     </key>
+    <key name="composer-attribution-language" type="s">
+      <default>''</default>
+      <_summary>Forward and reply attribution language tag, like en_US. Empty string means to use the same 
language as the user interface.</_summary>
+    </key>
     <key name="prompt-on-accel-send" type="b">
       <default>true</default>
       <_summary>Prompt on send when using key accelerator (Ctrl+Enter)</_summary>
diff --git a/src/addressbook/gui/contact-editor/test-editor.c 
b/src/addressbook/gui/contact-editor/test-editor.c
index e93d410d97..27aea80393 100644
--- a/src/addressbook/gui/contact-editor/test-editor.c
+++ b/src/addressbook/gui/contact-editor/test-editor.c
@@ -108,7 +108,7 @@ main (gint argc,
 
        gtk_main ();
 
-       e_util_cleanup_settings ();
+       e_misc_util_free_global_memory ();
 
        return 0;
 }
diff --git a/src/composer/e-composer-private.c b/src/composer/e-composer-private.c
index 5475ae7c68..66d6605a94 100644
--- a/src/composer/e-composer-private.c
+++ b/src/composer/e-composer-private.c
@@ -83,6 +83,105 @@ composer_update_gallery_visibility (EMsgComposer *composer)
        }
 }
 
+static gchar *
+e_composer_extract_lang_from_source (ESourceRegistry *registry,
+                                    const gchar *uid)
+{
+       ESource *source;
+       gchar *lang = NULL;
+
+       g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
+       g_return_val_if_fail (uid != NULL, NULL);
+
+       source = e_source_registry_ref_source (registry, uid);
+       if (source && e_source_has_extension (source, E_SOURCE_EXTENSION_MAIL_COMPOSITION)) {
+               ESourceMailComposition *mail_composition;
+
+               mail_composition = e_source_get_extension (source, E_SOURCE_EXTENSION_MAIL_COMPOSITION);
+               lang = e_source_mail_composition_dup_language (mail_composition);
+
+               if (lang && !*lang) {
+                       g_free (lang);
+                       lang = NULL;
+               }
+       }
+
+       g_clear_object (&source);
+
+       return lang;
+}
+
+static void
+e_composer_from_changed_cb (EComposerFromHeader *header,
+                           EMsgComposer *composer)
+{
+       gchar *current_uid;
+
+       g_return_if_fail (E_IS_MSG_COMPOSER (composer));
+
+       current_uid = e_composer_from_header_dup_active_id (header, NULL, NULL);
+
+       if (current_uid && g_strcmp0 (composer->priv->previous_identity_uid, current_uid) != 0) {
+               gchar *previous_lang = NULL, *current_lang = NULL;
+               ESourceRegistry *registry;
+
+               registry = e_composer_header_get_registry (E_COMPOSER_HEADER (header));
+
+               if (composer->priv->previous_identity_uid)
+                       previous_lang = e_composer_extract_lang_from_source (registry, 
composer->priv->previous_identity_uid);
+
+               current_lang = e_composer_extract_lang_from_source (registry, current_uid);
+
+               if (g_strcmp0 (previous_lang, current_lang) != 0) {
+                       GSettings *settings;
+                       gchar **strv;
+                       gboolean have_previous, have_current;
+                       gint ii;
+
+                       settings = e_util_ref_settings ("org.gnome.evolution.mail");
+                       strv = g_settings_get_strv (settings, "composer-spell-languages");
+                       g_object_unref (settings);
+
+                       have_previous = !previous_lang;
+                       have_current = !current_lang;
+
+                       for (ii = 0; strv && strv[ii] && (!have_previous || !have_current); ii++) {
+                               have_previous = have_previous || g_strcmp0 (previous_lang, strv[ii]) == 0;
+                               have_current = have_current || g_strcmp0 (current_lang, strv[ii]) == 0;
+                       }
+
+                       g_strfreev (strv);
+
+                       if (!have_previous || !have_current) {
+                               ESpellChecker *spell_checker;
+                               EHTMLEditor *editor;
+
+                               editor = e_msg_composer_get_editor (composer);
+                               spell_checker = e_content_editor_ref_spell_checker 
(e_html_editor_get_content_editor (editor));
+
+                               if (!have_previous)
+                                       e_spell_checker_set_language_active (spell_checker, previous_lang, 
FALSE);
+
+                               if (!have_current)
+                                       e_spell_checker_set_language_active (spell_checker, current_lang, 
TRUE);
+
+                               g_clear_object (&spell_checker);
+
+                               e_html_editor_update_spell_actions (editor);
+                               g_signal_emit_by_name (editor, "spell-languages-changed");
+                       }
+               }
+
+               g_free (previous_lang);
+               g_free (current_lang);
+
+               g_free (composer->priv->previous_identity_uid);
+               composer->priv->previous_identity_uid = current_uid;
+       } else {
+               g_free (current_uid);
+       }
+}
+
 void
 e_composer_private_constructed (EMsgComposer *composer)
 {
@@ -307,6 +406,9 @@ e_composer_private_constructed (EMsgComposer *composer)
                                        action, "active",
                                        G_BINDING_BIDIRECTIONAL |
                                        G_BINDING_SYNC_CREATE);
+
+                               g_signal_connect (header, "changed",
+                                       G_CALLBACK (e_composer_from_changed_cb), composer);
                                continue;
 
                        case E_COMPOSER_HEADER_BCC:
@@ -449,6 +551,7 @@ e_composer_private_finalize (EMsgComposer *composer)
        g_free (composer->priv->charset);
        g_free (composer->priv->mime_type);
        g_free (composer->priv->mime_body);
+       g_free (composer->priv->previous_identity_uid);
 }
 
 gchar *
diff --git a/src/composer/e-composer-private.h b/src/composer/e-composer-private.h
index 9ceb900e22..4a2e2e3e06 100644
--- a/src/composer/e-composer-private.h
+++ b/src/composer/e-composer-private.h
@@ -119,6 +119,8 @@ struct _EMsgComposerPrivate {
        gulong notify_subject_changed_handler;
 
        gulong drag_data_received_handler_id;
+
+       gchar *previous_identity_uid;
 };
 
 void           e_composer_private_constructed  (EMsgComposer *composer);
diff --git a/src/e-util/e-html-editor-actions.c b/src/e-util/e-html-editor-actions.c
index e32249eb17..8f7eeceed4 100644
--- a/src/e-util/e-html-editor-actions.c
+++ b/src/e-util/e-html-editor-actions.c
@@ -1999,3 +1999,41 @@ editor_actions_bind (EHTMLEditor *editor)
                editor->priv->suggestion_actions, "sensitive",
                G_BINDING_SYNC_CREATE);
 }
+
+void
+editor_actions_update_spellcheck_languages_menu (EHTMLEditor *editor,
+                                                const gchar * const *languages)
+{
+       GHashTable *active;
+       GList *actions, *link;
+       gint ii;
+
+       g_return_if_fail (E_IS_HTML_EDITOR (editor));
+
+       active = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+       for (ii = 0; languages && languages[ii]; ii++) {
+               g_hash_table_insert (active, g_strdup (languages[ii]), NULL);
+       }
+
+       actions = gtk_action_group_list_actions (editor->priv->language_actions);
+       for (link = actions; link; link = g_list_next (link)) {
+               GtkToggleAction *toggle_action;
+               gboolean is_active;
+
+               if (!GTK_IS_TOGGLE_ACTION (link->data))
+                       continue;
+
+               is_active = g_hash_table_contains (active, gtk_action_get_name (link->data));
+               toggle_action = GTK_TOGGLE_ACTION (link->data);
+
+               if ((gtk_toggle_action_get_active (toggle_action) ? 1 : 0) != (is_active ? 1 : 0)) {
+                       g_signal_handlers_block_by_func (toggle_action, action_language_cb, editor);
+                       gtk_toggle_action_set_active (toggle_action, is_active);
+                       g_signal_handlers_unblock_by_func (toggle_action, action_language_cb, editor);
+               }
+       }
+
+       g_hash_table_destroy (active);
+       g_list_free (actions);
+}
diff --git a/src/e-util/e-html-editor-private.h b/src/e-util/e-html-editor-private.h
index 733bec0317..b652f0a538 100644
--- a/src/e-util/e-html-editor-private.h
+++ b/src/e-util/e-html-editor-private.h
@@ -97,6 +97,9 @@ struct _EHTMLEditorPrivate {
 
 void           editor_actions_init             (EHTMLEditor *editor);
 void           editor_actions_bind             (EHTMLEditor *editor);
+void           editor_actions_update_spellcheck_languages_menu
+                                               (EHTMLEditor *editor,
+                                                const gchar * const *languages);
 const gchar *  e_html_editor_get_content_editor_name
                                                (EHTMLEditor *editor);
 
diff --git a/src/e-util/e-html-editor.c b/src/e-util/e-html-editor.c
index 9b46be681c..e4a7538ac9 100644
--- a/src/e-util/e-html-editor.c
+++ b/src/e-util/e-html-editor.c
@@ -485,6 +485,7 @@ html_editor_spell_languages_changed (EHTMLEditor *editor)
                        E_HTML_EDITOR_SPELL_CHECK_DIALOG (
                        editor->priv->spell_check_dialog));
 
+       editor_actions_update_spellcheck_languages_menu (editor, (const gchar * const *) languages);
        g_clear_object (&spell_checker);
        g_strfreev (languages);
 }
diff --git a/src/e-util/e-misc-utils.c b/src/e-util/e-misc-utils.c
index fffd9207bf..21896b470b 100644
--- a/src/e-util/e-misc-utils.c
+++ b/src/e-util/e-misc-utils.c
@@ -63,6 +63,8 @@
 #include "e-client-cache.h"
 #include "e-filter-option.h"
 #include "e-mktemp.h"
+#include "e-simple-async-result.h"
+#include "e-spell-checker.h"
 #include "e-util-private.h"
 #include "e-xml-utils.h"
 
@@ -4236,3 +4238,304 @@ e_util_query_ldap_root_dse_sync (const gchar *host,
        return FALSE;
 #endif
 }
+
+static GHashTable *iso_639_table = NULL;
+static GHashTable *iso_3166_table = NULL;
+
+#ifdef HAVE_ISO_CODES
+
+#define ISOCODESLOCALEDIR ISO_CODES_PREFIX "/share/locale"
+
+#ifdef G_OS_WIN32
+#ifdef DATADIR
+#undef DATADIR
+#endif
+#include <shlobj.h>
+
+static gchar *
+_get_iso_codes_prefix (void)
+{
+       static gchar retval[1000];
+       static gint beenhere = 0;
+       gchar *temp_dir = 0;
+
+       if (beenhere)
+               return retval;
+
+       if (!(temp_dir = g_win32_get_package_installation_directory_of_module (_e_get_dll_hmodule ()))) {
+               strcpy (retval, ISO_CODES_PREFIX);
+               return retval;
+       }
+
+       strcpy (retval, temp_dir);
+       g_free (temp_dir);
+       beenhere = 1;
+       return retval;
+}
+
+static gchar *
+_get_isocodeslocaledir (void)
+{
+       static gchar retval[1000];
+       static gint beenhere = 0;
+
+       if (beenhere)
+               return retval;
+
+       g_snprintf (retval, sizeof (retval), "%s\\share\\locale", _get_iso_codes_prefix ());
+       beenhere = 1;
+       return retval;
+}
+
+#undef ISO_CODES_PREFIX
+#define ISO_CODES_PREFIX _get_iso_codes_prefix ()
+
+#undef ISOCODESLOCALEDIR
+#define ISOCODESLOCALEDIR _get_isocodeslocaledir ()
+
+#endif
+
+#define ISO_639_DOMAIN "iso_639"
+#define ISO_3166_DOMAIN        "iso_3166"
+
+static void
+iso_639_start_element (GMarkupParseContext *context,
+                       const gchar *element_name,
+                       const gchar **attribute_names,
+                       const gchar **attribute_values,
+                       gpointer data,
+                       GError **error)
+{
+       GHashTable *hash_table = data;
+       const gchar *iso_639_1_code = NULL;
+       const gchar *iso_639_2_code = NULL;
+       const gchar *name = NULL;
+       const gchar *code = NULL;
+       gint ii;
+
+       if (g_strcmp0 (element_name, "iso_639_entry") != 0) {
+               return;
+       }
+
+       for (ii = 0; attribute_names[ii] != NULL; ii++) {
+               if (strcmp (attribute_names[ii], "name") == 0)
+                       name = attribute_values[ii];
+               else if (strcmp (attribute_names[ii], "iso_639_1_code") == 0)
+                       iso_639_1_code = attribute_values[ii];
+               else if (strcmp (attribute_names[ii], "iso_639_2T_code") == 0)
+                       iso_639_2_code = attribute_values[ii];
+       }
+
+       code = (iso_639_1_code != NULL) ? iso_639_1_code : iso_639_2_code;
+
+       if (code != NULL && *code != '\0' && name != NULL && *name != '\0')
+               g_hash_table_insert (
+                       hash_table, g_strdup (code),
+                       g_strdup (dgettext (ISO_639_DOMAIN, name)));
+}
+
+static void
+iso_3166_start_element (GMarkupParseContext *context,
+                        const gchar *element_name,
+                        const gchar **attribute_names,
+                        const gchar **attribute_values,
+                        gpointer data,
+                        GError **error)
+{
+       GHashTable *hash_table = data;
+       const gchar *name = NULL;
+       const gchar *code = NULL;
+       gint ii;
+
+       if (strcmp (element_name, "iso_3166_entry") != 0)
+               return;
+
+       for (ii = 0; attribute_names[ii] != NULL; ii++) {
+               if (strcmp (attribute_names[ii], "name") == 0)
+                       name = attribute_values[ii];
+               else if (strcmp (attribute_names[ii], "alpha_2_code") == 0)
+                       code = attribute_values[ii];
+       }
+
+       if (code != NULL && *code != '\0' && name != NULL && *name != '\0')
+               g_hash_table_insert (
+                       hash_table, g_ascii_strdown (code, -1),
+                       g_strdup (dgettext (ISO_3166_DOMAIN, name)));
+}
+
+static GMarkupParser iso_639_parser = {
+       iso_639_start_element,
+       NULL, NULL, NULL, NULL
+};
+
+static GMarkupParser iso_3166_parser = {
+       iso_3166_start_element,
+       NULL, NULL, NULL, NULL
+};
+
+static void
+iso_codes_parse (const GMarkupParser *parser,
+                 const gchar *basename,
+                 GHashTable *hash_table)
+{
+       GMappedFile *mapped_file;
+       gchar *filename;
+       GError *error = NULL;
+
+       filename = g_build_filename (
+               ISO_CODES_PREFIX, "share", "xml",
+               "iso-codes", basename, NULL);
+       mapped_file = g_mapped_file_new (filename, FALSE, &error);
+       g_free (filename);
+
+       if (mapped_file != NULL) {
+               GMarkupParseContext *context;
+               const gchar *contents;
+               gsize length;
+
+               context = g_markup_parse_context_new (
+                       parser, 0, hash_table, NULL);
+               contents = g_mapped_file_get_contents (mapped_file);
+               length = g_mapped_file_get_length (mapped_file);
+               g_markup_parse_context_parse (
+                       context, contents, length, &error);
+               g_markup_parse_context_free (context);
+#if GLIB_CHECK_VERSION(2,21,3)
+               g_mapped_file_unref (mapped_file);
+#else
+               g_mapped_file_free (mapped_file);
+#endif
+       }
+
+       if (error != NULL) {
+               g_warning ("%s: %s", basename, error->message);
+               g_error_free (error);
+       }
+}
+
+#endif /* HAVE_ISO_CODES */
+
+/**
+ * e_util_get_language_name:
+ * @language_tag: Language tag to get its name for
+ *
+ * Returns: (transfer full): Newly allocated string with localized language name
+ *
+ * Since: 3.32
+ **/
+gchar *
+e_util_get_language_name (const gchar *language_tag)
+{
+       const gchar *iso_639_name;
+       const gchar *iso_3166_name;
+       gchar *language_name;
+       gchar *lowercase;
+       gchar **tokens;
+
+       g_return_val_if_fail (language_tag != NULL, NULL);
+
+       /* Split language code into lowercase tokens. */
+       lowercase = g_ascii_strdown (language_tag, -1);
+       tokens = g_strsplit (lowercase, "_", -1);
+       g_free (lowercase);
+
+       g_return_val_if_fail (tokens != NULL, NULL);
+
+       if (!iso_639_table && !iso_3166_table) {
+#if defined (ENABLE_NLS) && defined (HAVE_ISO_CODES)
+               bindtextdomain (ISO_639_DOMAIN, ISOCODESLOCALEDIR);
+               bind_textdomain_codeset (ISO_639_DOMAIN, "UTF-8");
+
+               bindtextdomain (ISO_3166_DOMAIN, ISOCODESLOCALEDIR);
+               bind_textdomain_codeset (ISO_3166_DOMAIN, "UTF-8");
+#endif /* ENABLE_NLS && HAVE_ISO_CODES */
+
+               iso_639_table = g_hash_table_new_full (
+                       (GHashFunc) g_str_hash,
+                       (GEqualFunc) g_str_equal,
+                       (GDestroyNotify) g_free,
+                       (GDestroyNotify) g_free);
+
+               iso_3166_table = g_hash_table_new_full (
+                       (GHashFunc) g_str_hash,
+                       (GEqualFunc) g_str_equal,
+                       (GDestroyNotify) g_free,
+                       (GDestroyNotify) g_free);
+
+#ifdef HAVE_ISO_CODES
+               iso_codes_parse (
+                       &iso_639_parser, "iso_639.xml", iso_639_table);
+               iso_codes_parse (
+                       &iso_3166_parser, "iso_3166.xml", iso_3166_table);
+#endif /* HAVE_ISO_CODES */
+       }
+
+       iso_639_name = g_hash_table_lookup (iso_639_table, tokens[0]);
+
+       if (iso_639_name == NULL) {
+               language_name = g_strdup_printf (
+               /* Translators: %s is the language ISO code. */
+                       C_("language", "Unknown (%s)"), language_tag);
+               goto exit;
+       }
+
+       if (g_strv_length (tokens) < 2) {
+               language_name = g_strdup (iso_639_name);
+               goto exit;
+       }
+
+       iso_3166_name = g_hash_table_lookup (iso_3166_table, tokens[1]);
+
+       if (iso_3166_name != NULL)
+               language_name = g_strdup_printf (
+                /* Translators: The first %s is the language name, and the
+                * second is the country name. Example: "French (France)" */
+                       C_("language", "%s (%s)"), iso_639_name, iso_3166_name);
+       else
+               language_name = g_strdup_printf (
+                /* Translators: The first %s is the language name, and the
+                * second is the country name. Example: "French (France)" */
+                       C_("language", "%s (%s)"), iso_639_name, tokens[1]);
+
+ exit:
+       g_strfreev (tokens);
+
+       if (language_name) {
+               gchar *ptr;
+
+               /* When the name has two or more ';' then strip the string at the second of them */
+               ptr = strchr (language_name, ';');
+               if (ptr)
+                       ptr = strchr (ptr + 1, ';');
+               if (ptr)
+                       *ptr = '\0';
+       }
+
+       return language_name;
+}
+
+/**
+ * e_misc_util_free_global_memory:
+ *
+ * Frees global memory allocated by evolution-util library.
+ * This is usually called at the end of the application.
+ *
+ * Since: 3.32
+ **/
+void
+e_misc_util_free_global_memory (void)
+{
+       if (iso_639_table) {
+               g_hash_table_destroy (iso_639_table);
+               iso_639_table = NULL;
+       }
+
+       if (iso_3166_table) {
+               g_hash_table_destroy (iso_3166_table);
+               iso_3166_table = NULL;
+       }
+
+       e_util_cleanup_settings ();
+       e_spell_checker_free_global_memory ();
+       e_simple_async_result_free_global_memory ();
+}
diff --git a/src/e-util/e-misc-utils.h b/src/e-util/e-misc-utils.h
index e170e1993c..3b8e976758 100644
--- a/src/e-util/e-misc-utils.h
+++ b/src/e-util/e-misc-utils.h
@@ -347,6 +347,8 @@ gboolean    e_util_query_ldap_root_dse_sync (const gchar *host,
                                                 gchar ***out_root_dse,
                                                 GCancellable *cancellable,
                                                 GError **error);
+gchar *                e_util_get_language_name        (const gchar *language_tag);
+void           e_misc_util_free_global_memory  (void);
 
 G_END_DECLS
 
diff --git a/src/e-util/e-spell-checker.c b/src/e-util/e-spell-checker.c
index 5ae1fa66a4..3e121de430 100644
--- a/src/e-util/e-spell-checker.c
+++ b/src/e-util/e-spell-checker.c
@@ -429,7 +429,8 @@ e_spell_checker_get_language_active (ESpellChecker *checker,
        g_return_val_if_fail (language_code != NULL, FALSE);
 
        dictionary = e_spell_checker_ref_dictionary (checker, language_code);
-       g_return_val_if_fail (dictionary != NULL, FALSE);
+       if (!dictionary)
+               return FALSE;
 
        active_dictionaries = checker->priv->active_dictionaries;
        active = g_hash_table_contains (active_dictionaries, dictionary);
@@ -452,7 +453,8 @@ e_spell_checker_set_language_active (ESpellChecker *checker,
        g_return_if_fail (language_code != NULL);
 
        dictionary = e_spell_checker_ref_dictionary (checker, language_code);
-       g_return_if_fail (dictionary != NULL);
+       if (!dictionary)
+               return;
 
        active_dictionaries = checker->priv->active_dictionaries;
        is_active = g_hash_table_contains (active_dictionaries, dictionary);
diff --git a/src/e-util/e-spell-dictionary.c b/src/e-util/e-spell-dictionary.c
index a8f4df8a3f..4f0af47218 100644
--- a/src/e-util/e-spell-dictionary.c
+++ b/src/e-util/e-spell-dictionary.c
@@ -20,7 +20,7 @@
 
 #include <enchant.h>
 
-#include "e-util-private.h"
+#include "e-misc-utils.h"
 #include "e-spell-dictionary.h"
 #include "e-spell-checker.h"
 
@@ -50,187 +50,11 @@ struct _ESpellDictionaryPrivate {
        gchar *collate_key;
 };
 
-#define ISO_639_DOMAIN "iso_639"
-#define ISO_3166_DOMAIN        "iso_3166"
-
-static GHashTable *iso_639_table = NULL;
-static GHashTable *iso_3166_table = NULL;
-
 G_DEFINE_TYPE (
        ESpellDictionary,
        e_spell_dictionary,
        G_TYPE_OBJECT);
 
-#ifdef HAVE_ISO_CODES
-
-#define ISOCODESLOCALEDIR ISO_CODES_PREFIX "/share/locale"
-
-#ifdef G_OS_WIN32
-#ifdef DATADIR
-#undef DATADIR
-#endif
-#include <shlobj.h>
-
-static gchar *
-_get_iso_codes_prefix (void)
-{
-       static gchar retval[1000];
-       static gint beenhere = 0;
-       gchar *temp_dir = 0;
-
-       if (beenhere)
-               return retval;
-
-       if (!(temp_dir = g_win32_get_package_installation_directory_of_module (_e_get_dll_hmodule ()))) {
-               strcpy (retval, ISO_CODES_PREFIX);
-               return retval;
-       }
-
-       strcpy (retval, temp_dir);
-       g_free (temp_dir);
-       beenhere = 1;
-       return retval;
-}
-
-static gchar *
-_get_isocodeslocaledir (void)
-{
-       static gchar retval[1000];
-       static gint beenhere = 0;
-
-       if (beenhere)
-               return retval;
-
-       g_snprintf (retval, sizeof (retval), "%s\\share\\locale", _get_iso_codes_prefix ());
-       beenhere = 1;
-       return retval;
-}
-
-#undef ISO_CODES_PREFIX
-#define ISO_CODES_PREFIX _get_iso_codes_prefix ()
-
-#undef ISOCODESLOCALEDIR
-#define ISOCODESLOCALEDIR _get_isocodeslocaledir ()
-
-#endif
-
-static void
-iso_639_start_element (GMarkupParseContext *context,
-                       const gchar *element_name,
-                       const gchar **attribute_names,
-                       const gchar **attribute_values,
-                       gpointer data,
-                       GError **error)
-{
-       GHashTable *hash_table = data;
-       const gchar *iso_639_1_code = NULL;
-       const gchar *iso_639_2_code = NULL;
-       const gchar *name = NULL;
-       const gchar *code = NULL;
-       gint ii;
-
-       if (g_strcmp0 (element_name, "iso_639_entry") != 0) {
-               return;
-       }
-
-       for (ii = 0; attribute_names[ii] != NULL; ii++) {
-               if (strcmp (attribute_names[ii], "name") == 0)
-                       name = attribute_values[ii];
-               else if (strcmp (attribute_names[ii], "iso_639_1_code") == 0)
-                       iso_639_1_code = attribute_values[ii];
-               else if (strcmp (attribute_names[ii], "iso_639_2T_code") == 0)
-                       iso_639_2_code = attribute_values[ii];
-       }
-
-       code = (iso_639_1_code != NULL) ? iso_639_1_code : iso_639_2_code;
-
-       if (code != NULL && *code != '\0' && name != NULL && *name != '\0')
-               g_hash_table_insert (
-                       hash_table, g_strdup (code),
-                       g_strdup (dgettext (ISO_639_DOMAIN, name)));
-}
-
-static void
-iso_3166_start_element (GMarkupParseContext *context,
-                        const gchar *element_name,
-                        const gchar **attribute_names,
-                        const gchar **attribute_values,
-                        gpointer data,
-                        GError **error)
-{
-       GHashTable *hash_table = data;
-       const gchar *name = NULL;
-       const gchar *code = NULL;
-       gint ii;
-
-       if (strcmp (element_name, "iso_3166_entry") != 0)
-               return;
-
-       for (ii = 0; attribute_names[ii] != NULL; ii++) {
-               if (strcmp (attribute_names[ii], "name") == 0)
-                       name = attribute_values[ii];
-               else if (strcmp (attribute_names[ii], "alpha_2_code") == 0)
-                       code = attribute_values[ii];
-       }
-
-       if (code != NULL && *code != '\0' && name != NULL && *name != '\0')
-               g_hash_table_insert (
-                       hash_table, g_ascii_strdown (code, -1),
-                       g_strdup (dgettext (ISO_3166_DOMAIN, name)));
-}
-
-static GMarkupParser iso_639_parser = {
-       iso_639_start_element,
-       NULL, NULL, NULL, NULL
-};
-
-static GMarkupParser iso_3166_parser = {
-       iso_3166_start_element,
-       NULL, NULL, NULL, NULL
-};
-
-static void
-iso_codes_parse (const GMarkupParser *parser,
-                 const gchar *basename,
-                 GHashTable *hash_table)
-{
-       GMappedFile *mapped_file;
-       gchar *filename;
-       GError *error = NULL;
-
-       filename = g_build_filename (
-               ISO_CODES_PREFIX, "share", "xml",
-               "iso-codes", basename, NULL);
-       mapped_file = g_mapped_file_new (filename, FALSE, &error);
-       g_free (filename);
-
-       if (mapped_file != NULL) {
-               GMarkupParseContext *context;
-               const gchar *contents;
-               gsize length;
-
-               context = g_markup_parse_context_new (
-                       parser, 0, hash_table, NULL);
-               contents = g_mapped_file_get_contents (mapped_file);
-               length = g_mapped_file_get_length (mapped_file);
-               g_markup_parse_context_parse (
-                       context, contents, length, &error);
-               g_markup_parse_context_free (context);
-#if GLIB_CHECK_VERSION(2,21,3)
-               g_mapped_file_unref (mapped_file);
-#else
-               g_mapped_file_free (mapped_file);
-#endif
-       }
-
-       if (error != NULL) {
-               g_warning ("%s: %s", basename, error->message);
-               g_error_free (error);
-       }
-}
-
-#endif /* HAVE_ISO_CODES */
-
 struct _enchant_dict_description_data {
        gchar *language_tag;
        gchar *dict_name;
@@ -244,51 +68,9 @@ describe_dictionary (const gchar *language_tag,
                      gpointer user_data)
 {
        struct _enchant_dict_description_data *data = user_data;
-       const gchar *iso_639_name;
-       const gchar *iso_3166_name;
-       gchar *language_name;
-       gchar *lowercase;
-       gchar **tokens;
-
-       /* Split language code into lowercase tokens. */
-       lowercase = g_ascii_strdown (language_tag, -1);
-       tokens = g_strsplit (lowercase, "_", -1);
-       g_free (lowercase);
-
-       g_return_if_fail (tokens != NULL);
-
-       iso_639_name = g_hash_table_lookup (iso_639_table, tokens[0]);
-
-       if (iso_639_name == NULL) {
-               language_name = g_strdup_printf (
-               /* Translators: %s is the language ISO code. */
-                       C_("language", "Unknown (%s)"), language_tag);
-               goto exit;
-       }
-
-       if (g_strv_length (tokens) < 2) {
-               language_name = g_strdup (iso_639_name);
-               goto exit;
-       }
-
-       iso_3166_name = g_hash_table_lookup (iso_3166_table, tokens[1]);
-
-       if (iso_3166_name != NULL)
-               language_name = g_strdup_printf (
-                /* Translators: The first %s is the language name, and the
-                * second is the country name. Example: "French (France)" */
-                       C_("language", "%s (%s)"), iso_639_name, iso_3166_name);
-       else
-               language_name = g_strdup_printf (
-                /* Translators: The first %s is the language name, and the
-                * second is the country name. Example: "French (France)" */
-                       C_("language", "%s (%s)"), iso_639_name, tokens[1]);
-
-exit:
-       g_strfreev (tokens);
 
        data->language_tag = g_strdup (language_tag);
-       data->dict_name = language_name;
+       data->dict_name = e_util_get_language_name (language_tag);
 }
 
 static void
@@ -405,35 +187,6 @@ static void
 e_spell_dictionary_init (ESpellDictionary *dictionary)
 {
        dictionary->priv = E_SPELL_DICTIONARY_GET_PRIVATE (dictionary);
-
-       if (!iso_639_table && !iso_3166_table) {
-#if defined (ENABLE_NLS) && defined (HAVE_ISO_CODES)
-               bindtextdomain (ISO_639_DOMAIN, ISOCODESLOCALEDIR);
-               bind_textdomain_codeset (ISO_639_DOMAIN, "UTF-8");
-
-               bindtextdomain (ISO_3166_DOMAIN, ISOCODESLOCALEDIR);
-               bind_textdomain_codeset (ISO_3166_DOMAIN, "UTF-8");
-#endif /* ENABLE_NLS && HAVE_ISO_CODES */
-
-               iso_639_table = g_hash_table_new_full (
-                       (GHashFunc) g_str_hash,
-                       (GEqualFunc) g_str_equal,
-                       (GDestroyNotify) g_free,
-                       (GDestroyNotify) g_free);
-
-               iso_3166_table = g_hash_table_new_full (
-                       (GHashFunc) g_str_hash,
-                       (GEqualFunc) g_str_equal,
-                       (GDestroyNotify) g_free,
-                       (GDestroyNotify) g_free);
-
-#ifdef HAVE_ISO_CODES
-               iso_codes_parse (
-                       &iso_639_parser, "iso_639.xml", iso_639_table);
-               iso_codes_parse (
-                       &iso_3166_parser, "iso_3166.xml", iso_3166_table);
-#endif /* HAVE_ISO_CODES */
-       }
 }
 
 ESpellDictionary *
@@ -799,4 +552,3 @@ e_spell_dictionary_store_correction (ESpellDictionary *dictionary,
 
        g_object_unref (spell_checker);
 }
-
diff --git a/src/e-util/evolution-source-viewer.c b/src/e-util/evolution-source-viewer.c
index 069d6258a9..385146edb2 100644
--- a/src/e-util/evolution-source-viewer.c
+++ b/src/e-util/evolution-source-viewer.c
@@ -1177,7 +1177,7 @@ main (gint argc,
 
        gtk_main ();
 
-       e_util_cleanup_settings ();
+       e_misc_util_free_global_memory ();
 
        return 0;
 }
diff --git a/src/e-util/test-accounts-window.c b/src/e-util/test-accounts-window.c
index 80051e21b1..ca26579da6 100644
--- a/src/e-util/test-accounts-window.c
+++ b/src/e-util/test-accounts-window.c
@@ -70,7 +70,7 @@ main (gint argc,
        g_object_unref (registry);
 
        g_list_free_full (modules, (GDestroyNotify) g_type_module_unuse);
-       e_util_cleanup_settings ();
+       e_misc_util_free_global_memory ();
 
        return 0;
 }
diff --git a/src/e-util/test-calendar.c b/src/e-util/test-calendar.c
index d3683a0a25..031d39f174 100644
--- a/src/e-util/test-calendar.c
+++ b/src/e-util/test-calendar.c
@@ -96,7 +96,7 @@ main (gint argc,
 
        gtk_main ();
 
-       e_util_cleanup_settings ();
+       e_misc_util_free_global_memory ();
 
        return 0;
 }
diff --git a/src/e-util/test-category-completion.c b/src/e-util/test-category-completion.c
index e8b35d96d3..3b68e4ba59 100644
--- a/src/e-util/test-category-completion.c
+++ b/src/e-util/test-category-completion.c
@@ -62,7 +62,7 @@ main (gint argc,
 
        gtk_main ();
 
-       e_util_cleanup_settings ();
+       e_misc_util_free_global_memory ();
 
        return 0;
 }
diff --git a/src/e-util/test-contact-store.c b/src/e-util/test-contact-store.c
index cf391022a1..6f862efd8b 100644
--- a/src/e-util/test-contact-store.c
+++ b/src/e-util/test-contact-store.c
@@ -142,7 +142,7 @@ main (gint argc,
 
        gtk_main ();
 
-       e_util_cleanup_settings ();
+       e_misc_util_free_global_memory ();
 
        return 0;
 }
diff --git a/src/e-util/test-dateedit.c b/src/e-util/test-dateedit.c
index def69dbde9..9ffb9067e8 100644
--- a/src/e-util/test-dateedit.c
+++ b/src/e-util/test-dateedit.c
@@ -184,7 +184,7 @@ main (gint argc,
 
        gtk_main ();
 
-       e_util_cleanup_settings ();
+       e_misc_util_free_global_memory ();
 
        return 0;
 }
diff --git a/src/e-util/test-html-editor-units.c b/src/e-util/test-html-editor-units.c
index 63e5600d0f..9d3035f9bd 100644
--- a/src/e-util/test-html-editor-units.c
+++ b/src/e-util/test-html-editor-units.c
@@ -2906,8 +2906,7 @@ main (gint argc,
 
        res = g_test_run ();
 
-       e_util_cleanup_settings ();
-       e_spell_checker_free_global_memory ();
+       e_misc_util_free_global_memory ();
        test_utils_free_global_memory ();
 
        g_unlink (test_keyfile_filename);
diff --git a/src/e-util/test-html-editor.c b/src/e-util/test-html-editor.c
index c567c2808d..1e40fa0120 100644
--- a/src/e-util/test-html-editor.c
+++ b/src/e-util/test-html-editor.c
@@ -580,8 +580,7 @@ main (gint argc,
 
        gtk_main ();
 
-       e_util_cleanup_settings ();
-       e_spell_checker_free_global_memory ();
+       e_misc_util_free_global_memory ();
 
        return 0;
 }
diff --git a/src/e-util/test-mail-signatures.c b/src/e-util/test-mail-signatures.c
index 97702fb4e2..bfbea91ceb 100644
--- a/src/e-util/test-mail-signatures.c
+++ b/src/e-util/test-mail-signatures.c
@@ -190,7 +190,7 @@ main (gint argc,
 
        gtk_main ();
 
-       e_util_cleanup_settings ();
+       e_misc_util_free_global_memory ();
 
        return 0;
 }
diff --git a/src/e-util/test-name-selector.c b/src/e-util/test-name-selector.c
index feafaf79d2..0696e28be4 100644
--- a/src/e-util/test-name-selector.c
+++ b/src/e-util/test-name-selector.c
@@ -106,7 +106,7 @@ main (gint argc,
 
        g_object_unref (registry);
        g_object_unref (client_cache);
-       e_util_cleanup_settings ();
+       e_misc_util_free_global_memory ();
 
        return 0;
 }
diff --git a/src/e-util/test-preferences-window.c b/src/e-util/test-preferences-window.c
index 33bbd50e42..9b4c13c1b0 100644
--- a/src/e-util/test-preferences-window.c
+++ b/src/e-util/test-preferences-window.c
@@ -103,7 +103,7 @@ main (gint argc,
 
        gtk_main ();
 
-       e_util_cleanup_settings ();
+       e_misc_util_free_global_memory ();
 
        return 0;
 }
diff --git a/src/e-util/test-proxy-preferences.c b/src/e-util/test-proxy-preferences.c
index a072cc17a8..02c05bfd91 100644
--- a/src/e-util/test-proxy-preferences.c
+++ b/src/e-util/test-proxy-preferences.c
@@ -80,7 +80,7 @@ main (gint argc,
 
        gtk_main ();
 
-       e_util_cleanup_settings ();
+       e_misc_util_free_global_memory ();
 
        return 0;
 }
diff --git a/src/e-util/test-source-combo-box.c b/src/e-util/test-source-combo-box.c
index 334ba8667a..294c9d21f8 100644
--- a/src/e-util/test-source-combo-box.c
+++ b/src/e-util/test-source-combo-box.c
@@ -102,7 +102,7 @@ main (gint argc,
 
        gtk_main ();
 
-       e_util_cleanup_settings ();
+       e_misc_util_free_global_memory ();
 
        return 0;
 }
diff --git a/src/e-util/test-source-config.c b/src/e-util/test-source-config.c
index 9d41813caf..22e2003fa1 100644
--- a/src/e-util/test-source-config.c
+++ b/src/e-util/test-source-config.c
@@ -54,7 +54,7 @@ main (gint argc,
 
        gtk_main ();
 
-       e_util_cleanup_settings ();
+       e_misc_util_free_global_memory ();
 
        return 0;
 }
diff --git a/src/e-util/test-source-selector.c b/src/e-util/test-source-selector.c
index 49ed0d3862..2d5df38c0b 100644
--- a/src/e-util/test-source-selector.c
+++ b/src/e-util/test-source-selector.c
@@ -887,7 +887,7 @@ main (gint argc,
        gtk_main ();
 
        g_object_unref (registry);
-       e_util_cleanup_settings ();
+       e_misc_util_free_global_memory ();
 
        return 0;
 }
diff --git a/src/e-util/test-tree-view-frame.c b/src/e-util/test-tree-view-frame.c
index b9464bca97..b5bfa3ee61 100644
--- a/src/e-util/test-tree-view-frame.c
+++ b/src/e-util/test-tree-view-frame.c
@@ -371,7 +371,7 @@ main (gint argc,
 
        gtk_main ();
 
-       e_util_cleanup_settings ();
+       e_misc_util_free_global_memory ();
 
        return 0;
 }
diff --git a/src/mail/CMakeLists.txt b/src/mail/CMakeLists.txt
index c89e451225..32cb8a7923 100644
--- a/src/mail/CMakeLists.txt
+++ b/src/mail/CMakeLists.txt
@@ -219,6 +219,7 @@ target_compile_definitions(evolution-mail PRIVATE
        -DG_LOG_DOMAIN=\"evolution-mail\"
        -DEVOLUTION_PRIVDATADIR=\"${privdatadir}\"
        -DEVOLUTION_ETSPECDIR=\"${etspecdir}\"
+       -DEVOLUTION_LOCALEDIR=\"${LOCALE_INSTALL_DIR}\"
 )
 
 target_compile_options(evolution-mail PUBLIC
diff --git a/src/mail/e-mail-config-composing-page.c b/src/mail/e-mail-config-composing-page.c
index d00c45e0c3..394561fae6 100644
--- a/src/mail/e-mail-config-composing-page.c
+++ b/src/mail/e-mail-config-composing-page.c
@@ -21,6 +21,7 @@
 
 #include "e-mail-config-page.h"
 #include "e-mail-config-activity-page.h"
+#include "em-composer-utils.h"
 
 #include "e-mail-config-composing-page.h"
 
@@ -148,6 +149,16 @@ mail_config_composing_fill_reply_style_combox (GtkComboBoxText *combo)
        g_type_class_unref (enum_class);
 }
 
+static void
+mail_config_composing_fill_language_combox (GtkComboBoxText *combo)
+{
+       g_return_if_fail (GTK_IS_COMBO_BOX_TEXT (combo));
+
+       gtk_combo_box_text_append (combo, NULL, _("Use global setting"));
+
+       em_utils_add_installed_languages (combo);
+}
+
 static gboolean
 mail_config_composing_page_reply_style_to_string (GBinding *binding,
                                                 const GValue *source_value,
@@ -399,7 +410,7 @@ mail_config_composing_page_constructed (GObject *object)
        widget = gtk_label_new (markup);
        gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
        gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
-       gtk_grid_attach (GTK_GRID (container), widget, 0, 0, 1, 1);
+       gtk_grid_attach (GTK_GRID (container), widget, 0, 0, 2, 1);
        gtk_widget_show (widget);
        g_free (markup);
 
@@ -407,7 +418,7 @@ mail_config_composing_page_constructed (GObject *object)
        widget = gtk_label_new_with_mnemonic (text);
        gtk_widget_set_margin_left (widget, 12);
        gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
-       gtk_grid_attach (GTK_GRID (container), widget, 0, 1, 1, 1);
+       gtk_grid_attach (GTK_GRID (container), widget, 0, 1, 2, 1);
        gtk_widget_show (widget);
 
        label = GTK_LABEL (widget);
@@ -416,7 +427,7 @@ mail_config_composing_page_constructed (GObject *object)
        gtk_widget_set_hexpand (widget, TRUE);
        gtk_widget_set_margin_left (widget, 12);
        gtk_label_set_mnemonic_widget (label, widget);
-       gtk_grid_attach (GTK_GRID (container), widget, 0, 2, 1, 1);
+       gtk_grid_attach (GTK_GRID (container), widget, 0, 2, 2, 1);
        gtk_widget_show (widget);
 
        e_binding_bind_property_full (
@@ -432,7 +443,7 @@ mail_config_composing_page_constructed (GObject *object)
        widget = gtk_label_new_with_mnemonic (text);
        gtk_widget_set_margin_left (widget, 12);
        gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
-       gtk_grid_attach (GTK_GRID (container), widget, 0, 3, 1, 1);
+       gtk_grid_attach (GTK_GRID (container), widget, 0, 3, 2, 1);
        gtk_widget_show (widget);
 
        label = GTK_LABEL (widget);
@@ -441,7 +452,7 @@ mail_config_composing_page_constructed (GObject *object)
        gtk_widget_set_hexpand (widget, TRUE);
        gtk_widget_set_margin_left (widget, 12);
        gtk_label_set_mnemonic_widget (label, widget);
-       gtk_grid_attach (GTK_GRID (container), widget, 0, 4, 1, 1);
+       gtk_grid_attach (GTK_GRID (container), widget, 0, 4, 2, 1);
        gtk_widget_show (widget);
 
        e_binding_bind_property_full (
@@ -453,25 +464,21 @@ mail_config_composing_page_constructed (GObject *object)
                mail_config_composing_page_string_to_addrs,
                NULL, (GDestroyNotify) NULL);
 
-       widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
-       gtk_grid_attach (GTK_GRID (container), widget, 0, 5, 1, 1);
-       gtk_widget_show (widget);
-
-       container = widget;
-
        text = _("Re_ply style:");
        widget = gtk_label_new_with_mnemonic (text);
+       gtk_widget_set_hexpand (widget, FALSE);
        gtk_widget_set_margin_left (widget, 12);
        gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
-       gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+       gtk_grid_attach (GTK_GRID (container), widget, 0, 5, 1, 1);
        gtk_widget_show (widget);
 
        label = GTK_LABEL (widget);
 
        widget = gtk_combo_box_text_new ();
-       gtk_widget_set_hexpand (widget, FALSE);
+       gtk_widget_set_halign (widget, GTK_ALIGN_START);
+       gtk_widget_set_hexpand (widget, TRUE);
        gtk_label_set_mnemonic_widget (label, widget);
-       gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+       gtk_grid_attach (GTK_GRID (container), widget, 1, 5, 1, 1);
        gtk_widget_show (widget);
 
        mail_config_composing_fill_reply_style_combox (GTK_COMBO_BOX_TEXT (widget));
@@ -485,6 +492,35 @@ mail_config_composing_page_constructed (GObject *object)
                mail_config_composing_page_string_to_reply_style,
                NULL, (GDestroyNotify) NULL);
 
+       widget = gtk_label_new_with_mnemonic (_("Lang_uage:"));
+       gtk_widget_set_hexpand (widget, FALSE);
+       gtk_widget_set_margin_left (widget, 12);
+       gtk_widget_set_tooltip_text (widget, _("Language for Reply and Forward attribution text"));
+       gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
+       gtk_grid_attach (GTK_GRID (container), widget, 0, 6, 1, 1);
+       gtk_widget_show (widget);
+
+       label = GTK_LABEL (widget);
+
+       widget = gtk_combo_box_text_new ();
+       gtk_widget_set_halign (widget, GTK_ALIGN_START);
+       gtk_widget_set_hexpand (widget, TRUE);
+       gtk_widget_set_tooltip_text (widget, _("Language for Reply and Forward attribution text"));
+       gtk_label_set_mnemonic_widget (label, widget);
+       gtk_grid_attach (GTK_GRID (container), widget, 1, 6, 1, 1);
+       gtk_widget_show (widget);
+
+       mail_config_composing_fill_language_combox (GTK_COMBO_BOX_TEXT (widget));
+
+       e_binding_bind_property (
+               composition_ext, "language",
+               widget, "active-id",
+               G_BINDING_BIDIRECTIONAL |
+               G_BINDING_SYNC_CREATE);
+
+       if (gtk_combo_box_get_active (GTK_COMBO_BOX (widget)) == -1)
+               gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
+
        widget = gtk_check_button_new_with_mnemonic (_("Start _typing at the bottom"));
        gtk_widget_set_margin_left (widget, 12);
        gtk_box_pack_start (GTK_BOX (main_box), widget, FALSE, FALSE, 0);
diff --git a/src/mail/em-composer-utils.c b/src/mail/em-composer-utils.c
index 340dddabc4..5dadc5f5ad 100644
--- a/src/mail/em-composer-utils.c
+++ b/src/mail/em-composer-utils.c
@@ -23,6 +23,7 @@
 
 #include "evolution-config.h"
 
+#include <locale.h>
 #include <string.h>
 #include <gtk/gtk.h>
 #include <glib/gi18n.h>
@@ -2007,6 +2008,129 @@ traverse_parts (GSList *clues,
        }
 }
 
+static void
+emcu_change_locale (const gchar *lc_messages,
+                   const gchar *lc_time,
+                   gchar **out_lc_messages,
+                   gchar **out_lc_time)
+{
+       gboolean success;
+       gchar *previous;
+
+       if (lc_messages) {
+               #if defined(LC_MESSAGES)
+               previous = g_strdup (setlocale (LC_MESSAGES, NULL));
+               success = setlocale (LC_MESSAGES, lc_messages) != NULL;
+               #else
+               previous = g_strdup (setlocale (LC_ALL, NULL));
+               success = setlocale (LC_ALL, lc_messages) != NULL;
+               #endif
+
+               if (out_lc_messages)
+                       *out_lc_messages = success ? g_strdup (previous) : NULL;
+
+               g_free (previous);
+       }
+
+       if (lc_time) {
+               #if defined(LC_TIME)
+               previous = g_strdup (setlocale (LC_TIME, NULL));
+               success = setlocale (LC_ALL, lc_time) != NULL;
+               #elif defined(LC_MESSAGES)
+               previous = g_strdup (setlocale (LC_ALL, NULL));
+               success = setlocale (LC_ALL, lc_time) != NULL;
+               #else
+               previous = NULL;
+               success = FALSE;
+               #endif
+
+               if (out_lc_time)
+                       *out_lc_time = success ? g_strdup (previous) : NULL;
+
+               g_free (previous);
+       }
+}
+
+static void
+emcu_prepare_attribution_locale (EMsgComposer *composer,
+                                gchar **out_lc_messages,
+                                gchar **out_lc_time)
+{
+       EComposerHeaderTable *table;
+       ESource *source = NULL;
+       gchar *uid, *lang = NULL;
+
+       g_return_if_fail (out_lc_messages != NULL);
+       g_return_if_fail (out_lc_time != NULL);
+
+       if (!composer)
+               return;
+
+       table = e_msg_composer_get_header_table (composer);
+       uid = e_composer_header_table_dup_identity_uid (table, NULL, NULL);
+       if (uid)
+               source = e_composer_header_table_ref_source (table, uid);
+       g_free (uid);
+
+       if (source && e_source_has_extension (source, E_SOURCE_EXTENSION_MAIL_COMPOSITION)) {
+               ESourceMailComposition *extension;
+
+               extension = e_source_get_extension (source, E_SOURCE_EXTENSION_MAIL_COMPOSITION);
+               lang = e_source_mail_composition_dup_language (extension);
+       }
+
+       g_clear_object (&source);
+
+       if (!lang || !*lang) {
+               GSettings *settings;
+
+               g_free (lang);
+
+               settings = e_util_ref_settings ("org.gnome.evolution.mail");
+               lang = g_settings_get_string (settings, "composer-attribution-language");
+               g_object_unref (settings);
+
+               if (!lang || !*lang)
+                       g_clear_pointer (&lang, g_free);
+       }
+
+       if (!lang) {
+               /* Set the locale always, even when using the user interface
+                  language, because gettext() can return wrong text (in the previously
+                  used language) */
+               #if defined(LC_MESSAGES)
+               lang = g_strdup (setlocale (LC_MESSAGES, NULL));
+               #else
+               lang = g_strdup (setlocale (LC_ALL, NULL));
+               #endif
+       }
+
+       if (lang) {
+               if (!strchr (lang, '.')) {
+                       gchar *tmp;
+
+                       tmp = g_strconcat (lang, ".utf8", NULL);
+                       g_free (lang);
+                       lang = tmp;
+               }
+
+               emcu_change_locale (lang, lang, out_lc_messages, out_lc_time);
+
+               g_free (lang);
+       }
+}
+
+/* Takes ownership (frees) the 'restore_locale' */
+static void
+emcu_restore_locale_after_attribution (gchar *restore_lc_messages,
+                                      gchar *restore_lc_time)
+{
+       emcu_change_locale (restore_lc_messages, restore_lc_time, NULL, NULL);
+
+       g_free (restore_lc_messages);
+       g_free (restore_lc_time);
+}
+
 /* Editing messages... */
 
 typedef enum {
@@ -2041,9 +2165,11 @@ static struct {
 };
 
 static gchar *
-quoting_text (QuotingTextEnum type)
+quoting_text (QuotingTextEnum type,
+             EMsgComposer *composer)
 {
        GSettings *settings;
+       gchar *restore_lc_messages = NULL, *restore_lc_time = NULL;
        gchar *text;
 
        settings = e_util_ref_settings ("org.gnome.evolution.mail");
@@ -2055,11 +2181,19 @@ quoting_text (QuotingTextEnum type)
 
        g_free (text);
 
-       return g_strdup (_(conf_messages[type].message));
+       if (composer)
+               emcu_prepare_attribution_locale (composer, &restore_lc_messages, &restore_lc_time);
+
+       text = g_strdup (_(conf_messages[type].message));
+
+       emcu_restore_locale_after_attribution (restore_lc_messages, restore_lc_time);
+
+       return text;
 }
 
 /**
  * em_composer_utils_get_forward_marker:
+ * @composer: an #EMsgComposer from which to get the identity information
  *
  * Returns: (transfer full): a text marker which is used for inline forwarded messages.
  *   Free returned pointer with g_free(), when no longer needed.
@@ -2067,13 +2201,14 @@ quoting_text (QuotingTextEnum type)
  * Since: 3.24
  **/
 gchar *
-em_composer_utils_get_forward_marker (void)
+em_composer_utils_get_forward_marker (EMsgComposer *composer)
 {
-       return quoting_text (QUOTING_FORWARD);
+       return quoting_text (QUOTING_FORWARD, composer);
 }
 
 /**
  * em_composer_utils_get_original_marker:
+ * @composer: an #EMsgComposer from which to get the identity information
  *
  * Returns: (transfer full): a text marker which is used for inline message replies.
  *   Free returned pointer with g_free(), when no longer needed.
@@ -2081,9 +2216,9 @@ em_composer_utils_get_forward_marker (void)
  * Since: 3.24
  **/
 gchar *
-em_composer_utils_get_original_marker (void)
+em_composer_utils_get_original_marker (EMsgComposer *composer)
 {
-       return quoting_text (QUOTING_ORIGINAL);
+       return quoting_text (QUOTING_ORIGINAL, composer);
 }
 
 static gboolean
@@ -2461,7 +2596,7 @@ forward_non_attached (EMsgComposer *composer,
                       EMailForwardStyle style)
 {
        CamelSession *session;
-       gchar *text, *forward;
+       gchar *text, *forward, *subject;
        guint32 validity_found = 0;
        guint32 flags;
 
@@ -2474,16 +2609,17 @@ forward_non_attached (EMsgComposer *composer,
        if (style == E_MAIL_FORWARD_STYLE_QUOTED)
                flags |= E_MAIL_FORMATTER_QUOTE_FLAG_CITE;
 
-       forward = quoting_text (QUOTING_FORWARD);
+       /* Setup composer's From account before calling quoting_text(),
+          because quoting_text() relies on that account. */
+       subject = mail_tool_generate_forward_subject (message);
+       set_up_new_composer (composer, subject, folder, message, uid);
+       g_free (subject);
+
+       forward = quoting_text (QUOTING_FORWARD, composer);
        text = em_utils_message_to_html (session, message, forward, flags, NULL, NULL, NULL, &validity_found);
 
        if (text != NULL) {
                CamelDataWrapper *content;
-               gchar *subject;
-
-               subject = mail_tool_generate_forward_subject (message);
-               set_up_new_composer (composer, subject, folder, message, uid);
-               g_free (subject);
 
                content = camel_medium_get_content (CAMEL_MEDIUM (message));
 
@@ -3413,7 +3549,8 @@ static struct {
 };
 
 static gchar *
-attribution_format (CamelMimeMessage *message)
+attribution_format (EMsgComposer *composer,
+                   CamelMimeMessage *message)
 {
        register const gchar *inptr;
        const gchar *start;
@@ -3423,8 +3560,11 @@ attribution_format (CamelMimeMessage *message)
        struct tm tm;
        time_t date;
        gint type;
-       gchar *format = quoting_text (QUOTING_ATTRIBUTION);
+       gchar *format, *restore_lc_messages = NULL, *restore_lc_time = NULL;
+
+       emcu_prepare_attribution_locale (composer, &restore_lc_messages, &restore_lc_time);
 
+       format = quoting_text (QUOTING_ATTRIBUTION, NULL);
        str = g_string_new ("");
 
        date = camel_mime_message_get_date (message, &tzone);
@@ -3559,6 +3699,8 @@ attribution_format (CamelMimeMessage *message)
                }
        }
 
+       emcu_restore_locale_after_attribution (restore_lc_messages, restore_lc_time);
+
        s = str->str;
        g_string_free (str, FALSE);
        g_free (format);
@@ -3596,7 +3738,7 @@ composer_set_body (EMsgComposer *composer,
                g_object_unref (part);
                break;
        case E_MAIL_REPLY_STYLE_OUTLOOK:
-               original = quoting_text (QUOTING_ORIGINAL);
+               original = quoting_text (QUOTING_ORIGINAL, composer);
                text = em_utils_message_to_html (
                        session, message, original, E_MAIL_FORMATTER_QUOTE_FLAG_HEADERS | keep_sig_flag,
                        parts_list, NULL, NULL, &validity_found);
@@ -3609,7 +3751,7 @@ composer_set_body (EMsgComposer *composer,
        case E_MAIL_REPLY_STYLE_QUOTED:
        default:
                /* do what any sane user would want when replying... */
-               credits = attribution_format (message);
+               credits = attribution_format (composer, message);
                text = em_utils_message_to_html (
                        session, message, credits, E_MAIL_FORMATTER_QUOTE_FLAG_CITE | keep_sig_flag,
                        parts_list, NULL, NULL, &validity_found);
@@ -3623,24 +3765,6 @@ composer_set_body (EMsgComposer *composer,
        g_object_unref (session);
 }
 
-gchar *
-em_utils_construct_composer_text (CamelSession *session,
-                                  CamelMimeMessage *message,
-                                  EMailPartList *parts_list)
-{
-       gchar *text, *credits;
-
-       g_return_val_if_fail (CAMEL_IS_SESSION (session), NULL);
-
-       credits = attribution_format (message);
-       text = em_utils_message_to_html (
-               session, message, credits, E_MAIL_FORMATTER_QUOTE_FLAG_CITE,
-               parts_list, NULL, NULL, NULL);
-       g_free (credits);
-
-       return text;
-}
-
 static gboolean
 emcu_folder_is_inbox (CamelFolder *folder)
 {
@@ -4816,3 +4940,126 @@ em_utils_apply_send_account_override_to_composer (EMsgComposer *composer,
        g_free (alias_name);
        g_free (alias_address);
 }
+
+static GHashTable * /* gchar *lcmessages ~> gchar *localeID */
+em_enum_system_locales (void)
+{
+       GHashTable *locales;
+
+#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_hash_table_insert (locales, g_strdup (fullname), g_strdup (fullname));
+
+                               ident = g_strdup (fullname);
+                               at = strchr (ident, '@');
+                               if (at) {
+                                       *at = 0;
+                                       g_hash_table_insert (locales, g_strdup (ident), g_strdup (fullname));
+                               }
+
+                               ptr = strchr (ident, '_');
+                               if (ptr) {
+                                       *ptr = '\0';
+
+                                       g_hash_table_insert (locales, g_strdup (ident), g_strdup (fullname));
+
+                                       if (at)
+                                               g_hash_table_insert (locales, g_strconcat (ident, "@", at + 
1, NULL), g_strdup (fullname));
+                               }
+                       }
+
+                       g_free (fullname);
+                       g_free (ident);
+               }
+       }
+
+       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 (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));
+               }
+
+               g_free (filename);
+       }
+
+       g_hash_table_destroy (system_locales);
+       g_dir_close (dir);
+
+       langs = g_slist_sort (langs, (GCompareFunc) g_strcmp0);
+
+       for (link = langs; link; link = g_slist_next (link)) {
+               const gchar *lang = link->data;
+
+               if (lang) {
+                       gchar *lang_name;
+
+                       lang_name = e_util_get_language_name (lang);
+
+                       gtk_combo_box_text_append (combo, lang, lang_name && *lang_name ? lang_name : lang);
+                       n_langs++;
+
+                       g_free (lang_name);
+               }
+       }
+
+       g_slist_free_full (langs, g_free);
+
+       if (n_langs > 10)
+               gtk_combo_box_set_wrap_width (GTK_COMBO_BOX (combo), 5);
+}
diff --git a/src/mail/em-composer-utils.h b/src/mail/em-composer-utils.h
index 73e0760901..4f7e7f4b43 100644
--- a/src/mail/em-composer-utils.h
+++ b/src/mail/em-composer-utils.h
@@ -65,10 +65,6 @@ void         em_utils_forward_attachment     (EMsgComposer *composer,
                                                 GPtrArray *uids);
 void           em_utils_redirect_message       (EMsgComposer *composer,
                                                 CamelMimeMessage *message);
-gchar *                em_utils_construct_composer_text
-                                               (CamelSession *session,
-                                                CamelMimeMessage *message,
-                                                EMailPartList *source_formatter);
 gboolean       em_utils_is_munged_list_message (CamelMimeMessage *message);
 void           em_utils_get_reply_sender       (CamelMimeMessage *message,
                                                 CamelInternetAddress *to,
@@ -114,9 +110,10 @@ void               em_utils_apply_send_account_override_to_composer
                                                (EMsgComposer *composer,
                                                 CamelFolder *folder);
 gchar *                em_composer_utils_get_forward_marker
-                                               (void);
+                                               (EMsgComposer *composer);
 gchar *                em_composer_utils_get_original_marker
-                                               (void);
+                                               (EMsgComposer *composer);
+void           em_utils_add_installed_languages(GtkComboBoxText *combo);
 
 G_END_DECLS
 
diff --git a/src/mail/mail-config.ui b/src/mail/mail-config.ui
index 2f6a8293f4..bc81ff6e6a 100644
--- a/src/mail/mail-config.ui
+++ b/src/mail/mail-config.ui
@@ -517,6 +517,23 @@
                         <property name="y_options"/>
                       </packing>
                     </child>
+                    <child>
+                      <object class="GtkLabel" id="lblForwardReplyAttribLanguage">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">_Language:</property>
+                        <property name="tooltip-text" translatable="yes">Language for Reply and Forward 
attribution text</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">comboboxForwardReplyAttribLanguage</property>
+                        <property name="xalign">1</property>
+                      </object>
+                      <packing>
+                        <property name="top_attach">2</property>
+                        <property name="bottom_attach">3</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"/>
+                      </packing>
+                    </child>
                     <child>
                       <object class="GtkCheckButton" id="chkReplyStartBottom">
                         <property name="label" translatable="yes">Start _typing at the bottom</property>
@@ -529,8 +546,8 @@
                       </object>
                       <packing>
                         <property name="right_attach">2</property>
-                        <property name="top_attach">2</property>
-                        <property name="bottom_attach">3</property>
+                        <property name="top_attach">3</property>
+                        <property name="bottom_attach">4</property>
                         <property name="y_options"/>
                       </packing>
                     </child>
@@ -546,8 +563,8 @@
                       </object>
                       <packing>
                         <property name="right_attach">2</property>
-                        <property name="top_attach">3</property>
-                        <property name="bottom_attach">4</property>
+                        <property name="top_attach">4</property>
+                        <property name="bottom_attach">5</property>
                         <property name="y_options"/>
                       </packing>
                     </child>
@@ -563,8 +580,8 @@
                       </object>
                       <packing>
                         <property name="right_attach">2</property>
-                        <property name="top_attach">4</property>
-                        <property name="bottom_attach">5</property>
+                        <property name="top_attach">5</property>
+                        <property name="bottom_attach">6</property>
                         <property name="y_options"/>
                       </packing>
                     </child>
@@ -580,8 +597,8 @@
                       </object>
                       <packing>
                         <property name="right_attach">2</property>
-                        <property name="top_attach">5</property>
-                        <property name="bottom_attach">6</property>
+                        <property name="top_attach">6</property>
+                        <property name="bottom_attach">7</property>
                         <property name="y_options"/>
                       </packing>
                     </child>
@@ -597,8 +614,8 @@
                       </object>
                       <packing>
                         <property name="right_attach">2</property>
-                        <property name="top_attach">6</property>
-                        <property name="bottom_attach">7</property>
+                        <property name="top_attach">7</property>
+                        <property name="bottom_attach">8</property>
                         <property name="y_options"/>
                       </packing>
                     </child>
@@ -614,8 +631,8 @@
                       </object>
                       <packing>
                         <property name="right_attach">2</property>
-                        <property name="top_attach">7</property>
-                        <property name="bottom_attach">8</property>
+                        <property name="top_attach">8</property>
+                        <property name="bottom_attach">9</property>
                         <property name="y_options"/>
                       </packing>
                     </child>
@@ -631,8 +648,8 @@
                       </object>
                       <packing>
                         <property name="right_attach">2</property>
-                        <property name="top_attach">8</property>
-                        <property name="bottom_attach">9</property>
+                        <property name="top_attach">9</property>
+                        <property name="bottom_attach">10</property>
                         <property name="y_options"/>
                       </packing>
                     </child>
@@ -685,6 +702,27 @@
                         <property name="bottom_attach">2</property>
                       </packing>
                     </child>
+                    <child>
+                      <object class="GtkAlignment" id="forward-reply-attrib-language-alignment">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="xalign">0</property>
+                        <property name="xscale">0</property>
+                        <child>
+                          <object class="GtkComboBoxText" id="comboboxForwardReplyAttribLanguage">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="tooltip-text" translatable="yes">Language for Reply and Forward 
attribution text</property>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">2</property>
+                        <property name="bottom_attach">3</property>
+                      </packing>
+                    </child>
                   </object>
                 </child>
               </object>
diff --git a/src/modules/backup-restore/evolution-backup-tool.c 
b/src/modules/backup-restore/evolution-backup-tool.c
index 0d30a7afc0..735b18459b 100644
--- a/src/modules/backup-restore/evolution-backup-tool.c
+++ b/src/modules/backup-restore/evolution-backup-tool.c
@@ -1072,7 +1072,7 @@ main (gint argc,
        gtk_main ();
 
        g_object_unref (cancellable);
-       e_util_cleanup_settings ();
+       e_misc_util_free_global_memory ();
 
        return result;
 }
diff --git a/src/modules/mail/em-composer-prefs.c b/src/modules/mail/em-composer-prefs.c
index 31d5484401..b411599595 100644
--- a/src/modules/mail/em-composer-prefs.c
+++ b/src/modules/mail/em-composer-prefs.c
@@ -41,6 +41,7 @@
 #include <mail/em-folder-selector.h>
 #include <mail/em-folder-tree.h>
 #include <mail/em-folder-tree-model.h>
+#include <mail/em-composer-utils.h>
 #include <mail/e-mail-backend.h>
 #include <mail/e-mail-junk-options.h>
 #include <mail/e-mail-ui-session.h>
@@ -1335,6 +1336,18 @@ em_composer_prefs_construct (EMComposerPrefs *prefs,
                widget, "active-id",
                G_SETTINGS_BIND_DEFAULT);
 
+       widget = e_builder_get_widget (prefs->builder, "comboboxForwardReplyAttribLanguage");
+       gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (widget), NULL, _("Same as user interface"));
+       em_utils_add_installed_languages (GTK_COMBO_BOX_TEXT (widget));
+
+       g_settings_bind (
+               settings, "composer-attribution-language",
+               widget, "active-id",
+               G_SETTINGS_BIND_DEFAULT);
+
+       if (gtk_combo_box_get_active (GTK_COMBO_BOX (widget)) == -1)
+               gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
+
        /* Signatures */
        container = e_builder_get_widget (
                prefs->builder, "signature-alignment");
diff --git a/src/plugins/attachment-reminder/attachment-reminder.c 
b/src/plugins/attachment-reminder/attachment-reminder.c
index fe3df782d4..129ee06d51 100644
--- a/src/plugins/attachment-reminder/attachment-reminder.c
+++ b/src/plugins/attachment-reminder/attachment-reminder.c
@@ -73,7 +73,7 @@ GtkWidget *   org_gnome_attachment_reminder_config_option
                                         EConfigHookItemFactoryData *data);
 
 static gboolean ask_for_missing_attachment (EPlugin *ep, GtkWindow *widget);
-static gboolean check_for_attachment_clues (GByteArray *msg_text, guint32 ar_flags);
+static gboolean check_for_attachment_clues (EMsgComposer *composer, GByteArray *msg_text, guint32 ar_flags);
 static gboolean check_for_attachment (EMsgComposer *composer);
 static guint32 get_flags_from_composer (EMsgComposer *composer);
 static void commit_changes (UIData *ui);
@@ -101,7 +101,7 @@ org_gnome_evolution_attachment_reminder (EPlugin *ep,
                return;
 
        /* Set presend_check_status for the composer*/
-       if (check_for_attachment_clues (raw_msg_barray, get_flags_from_composer (t->composer))) {
+       if (check_for_attachment_clues (t->composer, raw_msg_barray, get_flags_from_composer (t->composer))) {
                if (!ask_for_missing_attachment (ep, (GtkWindow *) t->composer))
                        g_object_set_data (
                                G_OBJECT (t->composer),
@@ -239,7 +239,8 @@ censor_quoted_lines (GByteArray *msg_text,
 
 /* check for the clues */
 static gboolean
-check_for_attachment_clues (GByteArray *msg_text,
+check_for_attachment_clues (EMsgComposer *composer,
+                           GByteArray *msg_text,
                            guint32 ar_flags)
 {
        GSettings *settings;
@@ -248,9 +249,9 @@ check_for_attachment_clues (GByteArray *msg_text,
        gboolean found = FALSE;
 
        if (ar_flags == AR_IS_FORWARD)
-               marker = em_composer_utils_get_forward_marker ();
+               marker = em_composer_utils_get_forward_marker (composer);
        else if (ar_flags == AR_IS_REPLY)
-               marker = em_composer_utils_get_original_marker ();
+               marker = em_composer_utils_get_original_marker (composer);
 
        settings = e_util_ref_settings ("org.gnome.evolution.plugin.attachment-reminder");
 
diff --git a/src/shell/main.c b/src/shell/main.c
index d667fc47dd..abc140d55f 100644
--- a/src/shell/main.c
+++ b/src/shell/main.c
@@ -696,9 +696,7 @@ exit:
 
        gtk_accel_map_save (e_get_accels_filename ());
 
-       e_util_cleanup_settings ();
-       e_spell_checker_free_global_memory ();
-       e_simple_async_result_free_global_memory ();
+       e_misc_util_free_global_memory ();
 
        return 0;
 }


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