gtk: extract translations from Zig source code

This commit is contained in:
Leah Amelia Chen
2025-02-27 12:03:41 +01:00
parent 5851bad4a0
commit 9c97084ad0
5 changed files with 61 additions and 17 deletions

View File

@ -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 <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\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 ""

View File

@ -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;
}

View File

@ -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(&gtkTabNewClick), 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",

View File

@ -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;

View File

@ -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");
}