Skip to content

Commit 6865134

Browse files
MoDD0claude
andcommitted
feat: release 1.2.0 — toolbar button and custom keyboard shortcut
- Add translate-symbolic toolbar button in mail-preview-toolbar and browser window toolbars (main-toolbar-with/without-headerbar) - Add configurable keyboard shortcut via Translate Settings dialog; stored in GSettings, applied at startup via e_ui_action_set_accel() - Remove redundant Show Original shortcut (Translate already toggles) - Bump version to 1.2.0 in CMakeLists.txt, debian/changelog, CHANGELOG.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 0600744 commit 6865134

7 files changed

Lines changed: 195 additions & 5 deletions

File tree

CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ if(NOT DEFINED VERSION)
2727
if(DEB_VERSION)
2828
set(VERSION "${DEB_VERSION}")
2929
else()
30-
set(VERSION "1.0.0")
30+
set(VERSION "1.2.0")
3131
endif()
3232
else()
33-
set(VERSION "1.0.0")
33+
set(VERSION "1.2.0")
3434
endif()
3535
endif()
3636

data/gschema/org.gnome.evolution.translate.gschema.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
<summary>Preserve message formatting</summary>
1717
<description>Whether to attempt HTML-structure preserving translation.</description>
1818
</key>
19+
<key name="translate-shortcut" type="s">
20+
<default>'&lt;Alt&gt;&lt;Shift&gt;T'</default>
21+
<summary>Keyboard shortcut for Translate Message action</summary>
22+
</key>
1923
</schema>
2024

2125
<!-- Provider-specific (relocatable) schema example for Argos -->

debian/changelog

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
evolution-translate-extension (1.2.0-1) unstable; urgency=medium
2+
3+
* New features:
4+
- Toolbar button: Translate action appears in mail toolbar with icon
5+
- Custom keyboard shortcut configurable via Translate Settings dialog
6+
* Compatibility:
7+
- Full support for Evolution >= 3.56 EUIManager / EUIAction API
8+
- Maintains backward compatibility with Evolution < 3.56 (GtkUIManager)
9+
* Bug fixes:
10+
- Resolved issues #4, #5, #6; merged upstream PR #3
11+
- Fixed ArgosTranslate crash on Python 3.14 (spacy/pydantic conflict)
12+
- Stale translation state handling improvements
13+
14+
-- Andrea Costantino <andreaivancostantino@outlook.it> Sun, 01 Mar 2026 00:00:00 +0000
15+
116
evolution-translate-extension (1.0.0-1) unstable; urgency=medium
217

318
* Initial release

docs/CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
# Changelog
22

3+
## 1.2.0
4+
- **Toolbar button**: Translate action now appears directly in the mail toolbar
5+
with a `translate-symbolic` icon, next to Reply/Forward buttons.
6+
- **Custom keyboard shortcut**: Shortcut for the Translate action is now
7+
configurable via the Translate Settings dialog. Change takes effect after
8+
restarting Evolution.
9+
- **Evolution ≥ 3.56 compatibility**: Full support for the new EUIManager /
10+
EUIAction API that replaced GtkUIManager in Evolution 3.56. Plugin now works
11+
on both legacy (< 3.56) and modern Evolution builds.
12+
- **Bug fixes**: Resolved issues #4, #5, #6 and merged upstream PR #3
13+
(translation status messages, stale state handling, and other stability fixes).
14+
- **Manjaro / Arch installation guide** added to README.
15+
- **ArgosTranslate on Python 3.14**: Fixed crash caused by spacy/pydantic
16+
import error; uninstalling spacy from the venv resolves the issue.
17+
318
## 1.0.0
419
- Initial public release of Evolution Translation Extension.
520
- ArgosTranslate offline translation with HTML preservation.

src/translate-browser-extension.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ static const EUIActionEntry browser_entries[] = {
131131
NULL, N_("_Translate"), NULL, NULL,
132132
NULL, NULL, NULL, NULL },
133133
{ "translate-message-action",
134-
NULL, N_("_Translate"), NULL,
134+
"translate-symbolic", N_("_Translate"), NULL,
135135
N_("Translate the selected message"),
136136
action_translate_message_cb, NULL, NULL, NULL },
137137
{ "translate-show-original-action",
@@ -184,6 +184,18 @@ add_ui (TranslateBrowserExtension *self, EMailBrowser *browser)
184184
" </submenu>"
185185
" </placeholder>"
186186
" </menu>"
187+
" <toolbar id='main-toolbar-with-headerbar'>"
188+
" <placeholder id='mail-toolbar-common'>"
189+
" <separator/>"
190+
" <item action='translate-message-action'/>"
191+
" </placeholder>"
192+
" </toolbar>"
193+
" <toolbar id='main-toolbar-without-headerbar'>"
194+
" <placeholder id='mail-toolbar-common'>"
195+
" <separator/>"
196+
" <item action='translate-message-action'/>"
197+
" </placeholder>"
198+
" </toolbar>"
187199
"</eui>";
188200

189201
EMailReader *reader = E_MAIL_READER (browser);

src/translate-mail-ui.c

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,11 +146,11 @@ static const EUIActionEntry translate_entries[] = {
146146
NULL, N_("_Translate"), NULL, NULL,
147147
NULL, NULL, NULL, NULL },
148148
{ "translate-message-action",
149-
NULL, N_("_Translate Message"), "<Control><Shift>T",
149+
"translate-symbolic", N_("_Translate Message"), NULL,
150150
N_("Translate the selected message"),
151151
action_translate_message_cb, NULL, NULL, NULL },
152152
{ "translate-show-original-action",
153-
NULL, N_("Show _Original"), "<Control><Shift>O",
153+
NULL, N_("Show _Original"), NULL,
154154
N_("Show the original content"),
155155
action_show_original_cb, NULL, NULL, NULL },
156156
{ "translate-settings-action",
@@ -208,6 +208,12 @@ translate_mail_ui_init (EShellView *shell_view)
208208
" </submenu>"
209209
" </placeholder>"
210210
" </menu>"
211+
" <toolbar id='mail-preview-toolbar'>"
212+
" <placeholder id='mail-toolbar-common'>"
213+
" <separator/>"
214+
" <item action='translate-message-action'/>"
215+
" </placeholder>"
216+
" </toolbar>"
211217
"</eui>";
212218

213219
g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
@@ -221,6 +227,19 @@ translate_mail_ui_init (EShellView *shell_view)
221227
shell_view,
222228
eui_def);
223229

230+
/* Apply shortcuts from GSettings (allows user customization) */
231+
{
232+
GSettings *settings = g_settings_new ("org.gnome.evolution.translate");
233+
gchar *shortcut = g_settings_get_string (settings, "translate-shortcut");
234+
235+
EUIAction *translate_action = e_ui_manager_get_action (ui_manager, "translate-message-action");
236+
if (translate_action && shortcut && *shortcut)
237+
e_ui_action_set_accel (translate_action, shortcut);
238+
239+
g_free (shortcut);
240+
g_object_unref (settings);
241+
}
242+
224243
g_signal_connect (shell_view, "update-actions",
225244
G_CALLBACK (translate_mail_ui_update_actions_cb), NULL);
226245
}

src/translate-preferences.c

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <glib/gi18n-lib.h>
99
#include <gio/gio.h>
1010
#include <gtk/gtk.h>
11+
#include <gdk/gdkkeysyms.h>
1112

1213
#include "translate-preferences.h"
1314
#include "translate-utils.h"
@@ -29,6 +30,111 @@ static const Lang k_langs[] = {
2930
{"ja", N_("Japanese")}, {"ko", N_("Korean")}, {"zh", N_("Chinese")},
3031
};
3132

33+
/* ============================================================================
34+
* Shortcut capture button
35+
* ============================================================================ */
36+
37+
typedef struct {
38+
gchar *accel; /* current accelerator string, owned */
39+
gboolean capturing;
40+
gulong key_handler_id;
41+
GtkWidget *dialog;
42+
} ShortcutButtonData;
43+
44+
static void
45+
shortcut_button_data_free (gpointer ptr)
46+
{
47+
ShortcutButtonData *data = ptr;
48+
g_free (data->accel);
49+
g_free (data);
50+
}
51+
52+
static gboolean
53+
shortcut_key_press_cb (GtkWidget *widget,
54+
GdkEventKey *event,
55+
gpointer user_data)
56+
{
57+
GtkButton *button = GTK_BUTTON (user_data);
58+
ShortcutButtonData *data = g_object_get_data (G_OBJECT (button), "shortcut-data");
59+
60+
if (!data || !data->capturing)
61+
return FALSE;
62+
63+
/* Ignore standalone modifier key presses */
64+
if (event->is_modifier)
65+
return TRUE;
66+
67+
data->capturing = FALSE;
68+
g_signal_handler_disconnect (data->dialog, data->key_handler_id);
69+
data->key_handler_id = 0;
70+
71+
if (event->keyval == GDK_KEY_Escape) {
72+
/* Restore previous label */
73+
guint kval = 0;
74+
GdkModifierType mods = 0;
75+
if (data->accel && *data->accel)
76+
gtk_accelerator_parse (data->accel, &kval, &mods);
77+
gchar *label = kval ? gtk_accelerator_get_label (kval, mods)
78+
: g_strdup (data->accel && *data->accel ? data->accel : _("(none)"));
79+
gtk_button_set_label (button, label);
80+
g_free (label);
81+
} else {
82+
GdkModifierType mods = event->state & gtk_accelerator_get_default_mod_mask ();
83+
g_free (data->accel);
84+
data->accel = gtk_accelerator_name (event->keyval, mods);
85+
gchar *label = gtk_accelerator_get_label (event->keyval, mods);
86+
gtk_button_set_label (button, label);
87+
g_free (label);
88+
}
89+
90+
return TRUE;
91+
}
92+
93+
static void
94+
shortcut_button_clicked_cb (GtkButton *button,
95+
gpointer user_data)
96+
{
97+
ShortcutButtonData *data = g_object_get_data (G_OBJECT (button), "shortcut-data");
98+
99+
if (!data || data->capturing)
100+
return;
101+
102+
data->capturing = TRUE;
103+
gtk_button_set_label (button, _("Press shortcut\xe2\x80\xa6"));
104+
data->key_handler_id = g_signal_connect (data->dialog, "key-press-event",
105+
G_CALLBACK (shortcut_key_press_cb), button);
106+
}
107+
108+
static GtkWidget *
109+
create_shortcut_button (const gchar *accel,
110+
GtkWidget *dialog)
111+
{
112+
ShortcutButtonData *data = g_new0 (ShortcutButtonData, 1);
113+
data->accel = g_strdup (accel ? accel : "");
114+
data->capturing = FALSE;
115+
data->key_handler_id = 0;
116+
data->dialog = dialog;
117+
118+
guint kval = 0;
119+
GdkModifierType mods = 0;
120+
if (accel && *accel)
121+
gtk_accelerator_parse (accel, &kval, &mods);
122+
gchar *label = kval ? gtk_accelerator_get_label (kval, mods)
123+
: g_strdup (accel && *accel ? accel : _("(none)"));
124+
GtkWidget *button = gtk_button_new_with_label (label);
125+
g_free (label);
126+
127+
g_object_set_data_full (G_OBJECT (button), "shortcut-data", data,
128+
shortcut_button_data_free);
129+
g_signal_connect (button, "clicked", G_CALLBACK (shortcut_button_clicked_cb), NULL);
130+
131+
return button;
132+
}
133+
134+
/* ============================================================================
135+
* Preferences dialog
136+
* ============================================================================ */
137+
32138
void
33139
translate_preferences_show (GtkWindow *parent)
34140
{
@@ -73,13 +179,27 @@ translate_preferences_show (GtkWindow *parent)
73179
gboolean current_install_on_demand = g_settings_get_boolean (provider_settings, "install-on-demand");
74180
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (install_on_demand), current_install_on_demand);
75181

182+
/* Load current shortcut */
183+
g_autofree gchar *cur_translate_shortcut = g_settings_get_string (settings, "translate-shortcut");
184+
185+
GtkWidget *lbl_translate_shortcut = gtk_label_new (_("Translate shortcut:"));
186+
gtk_widget_set_halign (lbl_translate_shortcut, GTK_ALIGN_START);
187+
GtkWidget *translate_shortcut_btn = create_shortcut_button (cur_translate_shortcut, dlg);
188+
76189
gtk_grid_attach (GTK_GRID (grid), lbl_lang, 0, 0, 1, 1);
77190
gtk_grid_attach (GTK_GRID (grid), combo, 1, 0, 1, 1);
78191
gtk_grid_attach (GTK_GRID (grid), lbl_provider, 0, 1, 1, 1);
79192
gtk_grid_attach (GTK_GRID (grid), provider_combo, 1, 1, 1, 1);
80193
gtk_grid_attach (GTK_GRID (grid), lbl_venv, 0, 2, 1, 1);
81194
gtk_grid_attach (GTK_GRID (grid), venv_entry, 1, 2, 1, 1);
82195
gtk_grid_attach (GTK_GRID (grid), install_on_demand, 1, 3, 1, 1);
196+
GtkWidget *lbl_shortcut_hint = gtk_label_new ("Takes effect after restarting Evolution.");
197+
gtk_widget_set_halign (lbl_shortcut_hint, GTK_ALIGN_START);
198+
gtk_style_context_add_class (gtk_widget_get_style_context (lbl_shortcut_hint), "dim-label");
199+
200+
gtk_grid_attach (GTK_GRID (grid), lbl_translate_shortcut, 0, 4, 1, 1);
201+
gtk_grid_attach (GTK_GRID (grid), translate_shortcut_btn, 1, 4, 1, 1);
202+
gtk_grid_attach (GTK_GRID (grid), lbl_shortcut_hint, 1, 5, 1, 1);
83203

84204
gtk_widget_show_all (dlg);
85205
if (gtk_dialog_run (GTK_DIALOG (dlg)) == GTK_RESPONSE_OK) {
@@ -97,6 +217,11 @@ translate_preferences_show (GtkWindow *parent)
97217
gboolean install_enabled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (install_on_demand));
98218
g_settings_set_boolean (provider_settings, "install-on-demand", install_enabled);
99219

220+
/* Save shortcut */
221+
ShortcutButtonData *ts_data = g_object_get_data (G_OBJECT (translate_shortcut_btn), "shortcut-data");
222+
if (ts_data && ts_data->accel)
223+
g_settings_set_string (settings, "translate-shortcut", ts_data->accel);
224+
100225
/* venv_entry not yet implemented */
101226
(void)venv_entry;
102227
}

0 commit comments

Comments
 (0)