diff --git a/po/com.mitchellh.ghostty.pot b/po/com.mitchellh.ghostty.pot index 206528e37..870fa13f3 100644 --- a/po/com.mitchellh.ghostty.pot +++ b/po/com.mitchellh.ghostty.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: com.mitchellh.ghostty\n" "Report-Msgid-Bugs-To: m@mitchellh.com\n" -"POT-Creation-Date: 2025-02-26 14:34+0100\n" +"POT-Creation-Date: 2025-02-28 22:12+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -133,6 +133,7 @@ msgid "Terminal Inspector" msgstr "" #: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:102 +#: src/apprt/gtk/Window.zig:923 msgid "About Ghostty" msgstr "" @@ -176,3 +177,28 @@ msgid "" "Pasting this text into the terminal may be dangerous as it looks like some " "commands may be executed." msgstr "" + +#: src/apprt/gtk/Window.zig:192 +msgid "Main Menu" +msgstr "" + +#: src/apprt/gtk/Window.zig:212 +msgid "View Open Tabs" +msgstr "" + +#: src/apprt/gtk/Window.zig:257 +msgid "" +"⚠️ You're running a debug build of Ghostty! Performance will be degraded." +msgstr "" + +#: src/apprt/gtk/Window.zig:660 +msgid "Reloaded the configuration" +msgstr "" + +#: src/apprt/gtk/Window.zig:904 +msgid "Ghostty Developers" +msgstr "" + +#: src/apprt/gtk/Surface.zig:1236 +msgid "Copied to clipboard" +msgstr "" diff --git a/src/apprt/gtk/Surface.zig b/src/apprt/gtk/Surface.zig index dc8b11d31..401e695d0 100644 --- a/src/apprt/gtk/Surface.zig +++ b/src/apprt/gtk/Surface.zig @@ -33,6 +33,7 @@ const gtk_key = @import("key.zig"); const c = @import("c.zig").c; const Builder = @import("Builder.zig"); const adwaita = @import("adwaita.zig"); +const i18n = @import("i18n.zig"); const log = std.log.scoped(.gtk_surface); @@ -1232,7 +1233,7 @@ pub fn setClipboardString( self.app.config.@"app-notifications".@"clipboard-copy") { if (self.container.window()) |window| - window.sendToast("Copied to clipboard"); + window.sendToast(i18n._("Copied to clipboard")); } return; } diff --git a/src/apprt/gtk/Window.zig b/src/apprt/gtk/Window.zig index 2fe76fa6d..9b40b375f 100644 --- a/src/apprt/gtk/Window.zig +++ b/src/apprt/gtk/Window.zig @@ -33,6 +33,7 @@ const TabView = @import("TabView.zig"); const HeaderBar = @import("headerbar.zig"); const version = @import("version.zig"); const winproto = @import("winproto.zig"); +const i18n = @import("i18n.zig"); const log = std.log.scoped(.gtk); @@ -188,7 +189,7 @@ pub fn init(self: *Window, app: *App) !void { { const btn = c.gtk_menu_button_new(); - c.gtk_widget_set_tooltip_text(btn, "Main Menu"); + c.gtk_widget_set_tooltip_text(btn, i18n._("Main Menu")); c.gtk_menu_button_set_icon_name(@ptrCast(btn), "open-menu-symbolic"); c.gtk_menu_button_set_popover(@ptrCast(btn), @ptrCast(@alignCast(self.titlebar_menu.asWidget()))); _ = c.g_signal_connect_data( @@ -208,7 +209,7 @@ pub fn init(self: *Window, app: *App) !void { const btn = switch (self.config.gtk_tabs_location) { .top, .bottom => btn: { const btn = c.gtk_toggle_button_new(); - c.gtk_widget_set_tooltip_text(btn, "View Open Tabs"); + c.gtk_widget_set_tooltip_text(btn, i18n._("View Open Tabs")); c.gtk_button_set_icon_name(@ptrCast(btn), "view-grid-symbolic"); _ = c.g_object_bind_property( btn, @@ -235,7 +236,7 @@ pub fn init(self: *Window, app: *App) !void { { const btn = c.gtk_button_new_from_icon_name("tab-new-symbolic"); - c.gtk_widget_set_tooltip_text(btn, "New Tab"); + c.gtk_widget_set_tooltip_text(btn, i18n._("New Tab")); _ = c.g_signal_connect_data(btn, "clicked", c.G_CALLBACK(>kTabNewClick), self, null, c.G_CONNECT_DEFAULT); self.headerbar.packStart(btn); } @@ -253,7 +254,7 @@ pub fn init(self: *Window, app: *App) !void { // This is a really common issue where people build from source in debug and performance is really bad. if (comptime std.debug.runtime_safety) { const warning_box = c.gtk_box_new(c.GTK_ORIENTATION_VERTICAL, 0); - const warning_text = "⚠️ You're running a debug build of Ghostty! Performance will be degraded."; + const warning_text = i18n._("⚠️ You're running a debug build of Ghostty! Performance will be degraded."); if (adwaita.versionAtLeast(1, 3, 0)) { const banner = c.adw_banner_new(warning_text); c.adw_banner_set_revealed(@ptrCast(banner), 1); @@ -656,10 +657,10 @@ pub fn focusCurrentTab(self: *Window) void { } pub fn onConfigReloaded(self: *Window) void { - self.sendToast("Reloaded the configuration"); + self.sendToast(i18n._("Reloaded the configuration")); } -pub fn sendToast(self: *Window, title: [:0]const u8) void { +pub fn sendToast(self: *Window, title: [*:0]const u8) void { const toast = c.adw_toast_new(title); c.adw_toast_set_timeout(toast, 3); c.adw_toast_overlay_add_toast(@ptrCast(self.toast_overlay), toast); @@ -900,7 +901,7 @@ fn gtkActionAbout( "application-name", name, "developer-name", - "Ghostty Developers", + i18n._("Ghostty Developers"), "application-icon", icon, "version", @@ -919,7 +920,7 @@ fn gtkActionAbout( "logo-icon-name", icon, "title", - "About Ghostty", + i18n._("About Ghostty"), "version", build_config.version_string.ptr, "website", diff --git a/src/apprt/gtk/i18n.zig b/src/apprt/gtk/i18n.zig index a50a36154..4417796a7 100644 --- a/src/apprt/gtk/i18n.zig +++ b/src/apprt/gtk/i18n.zig @@ -33,3 +33,5 @@ pub fn init(alloc: std.mem.Allocator) !void { // as libintl.h isn't always easily available (e.g. in musl) extern fn bindtextdomain(domainname: [*:0]const u8, dirname: [*:0]const u8) ?[*:0]const u8; extern fn textdomain(domainname: [*:0]const u8) ?[*:0]const u8; +pub extern fn gettext(msgid: [*:0]const u8) [*:0]const u8; +pub const _ = gettext; diff --git a/src/build/GhosttyI18n.zig b/src/build/GhosttyI18n.zig index 8ec3efc3b..ae813ff35 100644 --- a/src/build/GhosttyI18n.zig +++ b/src/build/GhosttyI18n.zig @@ -15,7 +15,7 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyI18n { var steps = std.ArrayList(*std.Build.Step).init(b.allocator); errdefer steps.deinit(); - addUpdateStep(b); + try addUpdateStep(b); if (cfg.app_runtime == .gtk) { // Output the .mo files used by the GTK apprt @@ -41,10 +41,10 @@ pub fn install(self: *const GhosttyI18n) void { for (self.steps) |step| self.owner.getInstallStep().dependOn(step); } -fn addUpdateStep(b: *std.Build) void { +fn addUpdateStep(b: *std.Build) !void { const pot_step = b.step("update-translations", "Update translation files"); - const gettext = b.addSystemCommand(&.{ + const xgettext = b.addSystemCommand(&.{ "xgettext", "--language=C", // Silence the "unknown extension" errors "--from-code=UTF-8", @@ -63,13 +63,27 @@ fn addUpdateStep(b: *std.Build) void { // would be added to the file as its location, which differs for // everyone's checkout of the repository. // This comes at a cost of losing per-file caching, of course. - gettext.addArg(std.fmt.comptimePrint("src/apprt/gtk/ui/{[major]}.{[minor]}/{[name]s}.blp", blp)); + xgettext.addArg(std.fmt.comptimePrint("src/apprt/gtk/ui/{[major]}.{[minor]}/{[name]s}.blp", blp)); + } + + var gtk_files = try b.build_root.handle.openDir("src/apprt/gtk", .{ .iterate = true }); + defer gtk_files.close(); + + var walk = try gtk_files.walk(b.allocator); + defer walk.deinit(); + + while (try walk.next()) |src| { + switch (src.kind) { + .file => if (!std.mem.endsWith(u8, src.basename, ".zig")) continue, + else => continue, + } + xgettext.addArg((b.pathJoin(&.{ "src/apprt/gtk", src.path }))); } // Don't make Zig cache it - gettext.has_side_effects = true; + xgettext.has_side_effects = true; - const new_pot = gettext.captureStdOut(); + const new_pot = xgettext.captureStdOut(); const wf = b.addWriteFiles(); wf.addCopyFileToSource(new_pot, "po/" ++ domain ++ ".pot"); @@ -77,7 +91,7 @@ fn addUpdateStep(b: *std.Build) void { inline for (locales) |locale| { const msgmerge = b.addSystemCommand(&.{ "msgmerge", "-q" }); msgmerge.addFileArg(b.path("po/" ++ locale ++ ".po")); - msgmerge.addFileArg(gettext.captureStdOut()); + msgmerge.addFileArg(xgettext.captureStdOut()); wf.addCopyFileToSource(msgmerge.captureStdOut(), "po/" ++ locale ++ ".po"); }