mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
feat: initial implementation of i18n/l10n
This commit is contained in:
@ -41,6 +41,10 @@
|
|||||||
.url = "git+https://github.com/natecraddock/zf/?ref=main#ed99ca18b02dda052e20ba467e90b623c04690dd",
|
.url = "git+https://github.com/natecraddock/zf/?ref=main#ed99ca18b02dda052e20ba467e90b623c04690dd",
|
||||||
.hash = "1220edc3b8d8bedbb50555947987e5e8e2f93871ca3c8e8d4cc8f1377c15b5dd35e8",
|
.hash = "1220edc3b8d8bedbb50555947987e5e8e2f93871ca3c8e8d4cc8f1377c15b5dd35e8",
|
||||||
},
|
},
|
||||||
|
.zig_gettext = .{
|
||||||
|
.url = "git+https://github.com/pluiedev/zig-gettext/?ref=main#c1ff3a954ba0d9ad369ccf96810437c7e46cfc2a",
|
||||||
|
.hash = "122046140255a2dadfc3b3f55a68e750776f0ae2330865665f892d381d8d8f438c69",
|
||||||
|
},
|
||||||
|
|
||||||
// C libs
|
// C libs
|
||||||
.cimgui = .{ .path = "./pkg/cimgui" },
|
.cimgui = .{ .path = "./pkg/cimgui" },
|
||||||
@ -48,6 +52,7 @@
|
|||||||
.freetype = .{ .path = "./pkg/freetype" },
|
.freetype = .{ .path = "./pkg/freetype" },
|
||||||
.harfbuzz = .{ .path = "./pkg/harfbuzz" },
|
.harfbuzz = .{ .path = "./pkg/harfbuzz" },
|
||||||
.highway = .{ .path = "./pkg/highway" },
|
.highway = .{ .path = "./pkg/highway" },
|
||||||
|
.libintl = .{ .path = "./pkg/libintl" },
|
||||||
.libpng = .{ .path = "./pkg/libpng" },
|
.libpng = .{ .path = "./pkg/libpng" },
|
||||||
.macos = .{ .path = "./pkg/macos" },
|
.macos = .{ .path = "./pkg/macos" },
|
||||||
.oniguruma = .{ .path = "./pkg/oniguruma" },
|
.oniguruma = .{ .path = "./pkg/oniguruma" },
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
wayland,
|
wayland,
|
||||||
wayland-scanner,
|
wayland-scanner,
|
||||||
wayland-protocols,
|
wayland-protocols,
|
||||||
|
gettext,
|
||||||
}: let
|
}: let
|
||||||
# See package.nix. Keep in sync.
|
# See package.nix. Keep in sync.
|
||||||
rpathLibs =
|
rpathLibs =
|
||||||
@ -84,6 +85,7 @@
|
|||||||
gtk4
|
gtk4
|
||||||
glib
|
glib
|
||||||
wayland
|
wayland
|
||||||
|
gettext
|
||||||
];
|
];
|
||||||
in
|
in
|
||||||
mkShell {
|
mkShell {
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
pkg-config,
|
pkg-config,
|
||||||
zig_0_13,
|
zig_0_13,
|
||||||
pandoc,
|
pandoc,
|
||||||
|
gettext,
|
||||||
revision ? "dirty",
|
revision ? "dirty",
|
||||||
optimize ? "Debug",
|
optimize ? "Debug",
|
||||||
enableX11 ? true,
|
enableX11 ? true,
|
||||||
@ -56,6 +57,7 @@
|
|||||||
../images
|
../images
|
||||||
../include
|
../include
|
||||||
../pkg
|
../pkg
|
||||||
|
../po
|
||||||
../src
|
../src
|
||||||
../vendor
|
../vendor
|
||||||
../build.zig
|
../build.zig
|
||||||
@ -125,6 +127,7 @@ in
|
|||||||
pkg-config
|
pkg-config
|
||||||
zig_hook
|
zig_hook
|
||||||
wrapGAppsHook4
|
wrapGAppsHook4
|
||||||
|
gettext
|
||||||
]
|
]
|
||||||
++ lib.optionals enableWayland [
|
++ lib.optionals enableWayland [
|
||||||
wayland-scanner
|
wayland-scanner
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
# This file is auto-generated! check build-support/check-zig-cache-hash.sh for
|
# This file is auto-generated! check build-support/check-zig-cache-hash.sh for
|
||||||
# more details.
|
# more details.
|
||||||
"sha256-Bjy31evaKgpRX1mGwAFkai44eiiorTV1gW3VdP9Ins8="
|
"sha256-ar4f1+7Mx45K446X2/4/n9gVFZklAcQyJHQ+Ehn2p4U="
|
||||||
|
40
pkg/libintl/build.zig
Normal file
40
pkg/libintl/build.zig
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const dynamic_link_opts: std.Build.Module.LinkSystemLibraryOptions = .{
|
||||||
|
.preferred_link_mode = .dynamic,
|
||||||
|
.search_strategy = .mode_first,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn build(b: *std.Build) !void {
|
||||||
|
const target = b.standardTargetOptions(.{});
|
||||||
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
|
const module = b.addModule("intl", .{
|
||||||
|
.root_source_file = b.path("main.zig"),
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (b.systemIntegrationOption("libintl", .{
|
||||||
|
.default = !target.result.isGnuLibC(),
|
||||||
|
})) {
|
||||||
|
// On non-glibc platforms we don't have libintl
|
||||||
|
// built into libc, so we have to do more work.
|
||||||
|
// In GNU's infinite wisdom, there's no easy pkg-config file for
|
||||||
|
// you to consume and integrate into build systems other than autoconf.
|
||||||
|
// Users must rely on system library/include paths, or manually
|
||||||
|
// add libintl to the Zig search path.
|
||||||
|
module.linkSystemLibrary("intl", dynamic_link_opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
// switch (target.result.os.tag) {
|
||||||
|
// .windows => {
|
||||||
|
// const msys2 = b.dependency("libintl_msys2", .{});
|
||||||
|
// lib.addLibraryPath(msys2.path("usr/bin"));
|
||||||
|
// module.linkSystemLibrary2("msys-intl-8", .{
|
||||||
|
// .preferred_link_mode = .dynamic,
|
||||||
|
// .search_strategy = .mode_first,
|
||||||
|
// });
|
||||||
|
// },
|
||||||
|
// }
|
||||||
|
}
|
6
pkg/libintl/build.zig.zon
Normal file
6
pkg/libintl/build.zig.zon
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
.{
|
||||||
|
.name = "libintl",
|
||||||
|
.version = "0.0.1",
|
||||||
|
.paths = .{""},
|
||||||
|
.dependencies = .{},
|
||||||
|
}
|
41
pkg/libintl/c.zig
Normal file
41
pkg/libintl/c.zig
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
pub const locale = @cImport(@cInclude("locale.h"));
|
||||||
|
|
||||||
|
pub extern fn gettext(
|
||||||
|
msgid: [*:0]const u8,
|
||||||
|
) [*:0]const u8;
|
||||||
|
pub extern fn dgettext(
|
||||||
|
domainname: [*:0]const u8,
|
||||||
|
msgid: [*:0]const u8,
|
||||||
|
) [*:0]const u8;
|
||||||
|
pub extern fn dcgettext(
|
||||||
|
domainname: [*:0]const u8,
|
||||||
|
msgid: [*:0]const u8,
|
||||||
|
category: c_int,
|
||||||
|
) [*:0]const u8;
|
||||||
|
|
||||||
|
pub extern fn ngettext(
|
||||||
|
msgid1: [*:0]const u8,
|
||||||
|
msgid2: [*:0]const u8,
|
||||||
|
n: c_ulong,
|
||||||
|
) [*:0]const u8;
|
||||||
|
pub extern fn dngettext(
|
||||||
|
domainname: [*:0]const u8,
|
||||||
|
msgid1: [*:0]const u8,
|
||||||
|
msgid2: [*:0]const u8,
|
||||||
|
n: c_ulong,
|
||||||
|
) [*:0]const u8;
|
||||||
|
pub extern fn dcngettext(
|
||||||
|
domainname: [*:0]const u8,
|
||||||
|
msgid1: [*:0]const u8,
|
||||||
|
msgid2: [*:0]const u8,
|
||||||
|
n: c_ulong,
|
||||||
|
category: c_int,
|
||||||
|
) [*:0]const u8;
|
||||||
|
|
||||||
|
pub extern fn bindtextdomain(
|
||||||
|
domainname: [*:0]const u8,
|
||||||
|
dirname: [*:0]const u8,
|
||||||
|
) ?[*]const u8;
|
||||||
|
pub extern fn textdomain(
|
||||||
|
domainname: ?[*:0]const u8,
|
||||||
|
) ?[*]const u8;
|
73
pkg/libintl/main.zig
Normal file
73
pkg/libintl/main.zig
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const c = @import("c.zig");
|
||||||
|
|
||||||
|
pub const Category = enum(c_int) {
|
||||||
|
messages = c.locale.LC_MESSAGES,
|
||||||
|
collate = c.locale.LC_COLLATE,
|
||||||
|
ctype = c.locale.LC_CTYPE,
|
||||||
|
monetary = c.locale.LC_MONETARY,
|
||||||
|
numeric = c.locale.LC_NUMERIC,
|
||||||
|
time = c.locale.LC_TIME,
|
||||||
|
_,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Query = struct {
|
||||||
|
msg: [:0]const u8,
|
||||||
|
plural: ?struct {
|
||||||
|
msg: [:0]const u8,
|
||||||
|
number: c_ulong,
|
||||||
|
} = null,
|
||||||
|
domain: ?[:0]const u8 = null,
|
||||||
|
category: ?Category = null,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const _ = gettext;
|
||||||
|
|
||||||
|
pub fn gettext(comptime msg: [:0]const u8) [:0]const u8 {
|
||||||
|
return std.mem.span(c.gettext(msg));
|
||||||
|
}
|
||||||
|
pub fn dgettext(comptime msg: [:0]const u8, domain: [:0]const u8) [:0]const u8 {
|
||||||
|
return std.mem.span(c.dgettext(domain, msg));
|
||||||
|
}
|
||||||
|
pub fn dcgettext(comptime msg: [:0]const u8, domain: [:0]const u8, category: Category) [:0]const u8 {
|
||||||
|
return std.mem.span(c.dcgettext(domain, msg, category));
|
||||||
|
}
|
||||||
|
pub fn ngettext(
|
||||||
|
comptime msg: [:0]const u8,
|
||||||
|
comptime msg_plural: [:0]const u8,
|
||||||
|
number: c_ulong,
|
||||||
|
) [:0]const u8 {
|
||||||
|
return std.mem.span(c.ngettext(msg, msg_plural, number));
|
||||||
|
}
|
||||||
|
pub fn dngettext(
|
||||||
|
comptime msg: [:0]const u8,
|
||||||
|
comptime msg_plural: [:0]const u8,
|
||||||
|
number: c_ulong,
|
||||||
|
domain: [:0]const u8,
|
||||||
|
) [:0]const u8 {
|
||||||
|
return std.mem.span(c.dngettext(domain, msg, msg_plural, number));
|
||||||
|
}
|
||||||
|
pub fn dcngettext(
|
||||||
|
comptime msg: [:0]const u8,
|
||||||
|
comptime msg_plural: [:0]const u8,
|
||||||
|
number: c_ulong,
|
||||||
|
domain: [:0]const u8,
|
||||||
|
category: Category,
|
||||||
|
) [:0]const u8 {
|
||||||
|
return std.mem.span(c.dcngettext(
|
||||||
|
domain,
|
||||||
|
msg,
|
||||||
|
msg_plural,
|
||||||
|
number,
|
||||||
|
category,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bindTextDomain(domain: [:0]const u8, dir: [:0]const u8) std.mem.Allocator.Error!void {
|
||||||
|
// ENOMEM is the only possible error
|
||||||
|
if (c.bindtextdomain(domain, dir) == null) return error.OutOfMemory;
|
||||||
|
}
|
||||||
|
pub fn setTextDomain(domain: [:0]const u8) std.mem.Allocator.Error!void {
|
||||||
|
// ENOMEM is the only possible error
|
||||||
|
if (c.textdomain(domain) == null) return error.OutOfMemory;
|
||||||
|
}
|
0
po/LINGUAS
Normal file
0
po/LINGUAS
Normal file
159
po/messages.pot
Normal file
159
po/messages.pot
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Language: \n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/App.zig:1827 src/apprt/gtk/Window.zig:918
|
||||||
|
msgid "About Ghostty"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Tab.zig:147
|
||||||
|
msgid "All terminal sessions in this tab will be terminated."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Window.zig:800
|
||||||
|
msgid "All terminal sessions in this window will be terminated."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ClipboardConfirmationWindow.zig:170
|
||||||
|
msgid "Allow"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ClipboardConfirmationWindow.zig:248
|
||||||
|
msgid ""
|
||||||
|
"An application is attempting to read from the clipboard.\n"
|
||||||
|
"The current clipboard contents are shown below.\n"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ClipboardConfirmationWindow.zig:252
|
||||||
|
msgid ""
|
||||||
|
"An application is attempting to write to the clipboard.\n"
|
||||||
|
"The content to write is shown below.\n"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ClipboardConfirmationWindow.zig:237
|
||||||
|
msgid "Authorize Clipboard Access"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ClipboardConfirmationWindow.zig:169
|
||||||
|
msgid "Cancel"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/App.zig:1814
|
||||||
|
msgid "Close Tab"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/App.zig:1817
|
||||||
|
msgid "Close Window"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Tab.zig:143
|
||||||
|
msgid "Close this tab?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:728
|
||||||
|
msgid "Close this terminal?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Window.zig:796
|
||||||
|
msgid "Close this window?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:1141
|
||||||
|
msgid "Copied to clipboard"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/App.zig:1848
|
||||||
|
msgid "Copy"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ClipboardConfirmationWindow.zig:170
|
||||||
|
msgid "Deny"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Window.zig:899
|
||||||
|
msgid "Ghostty Developers"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/inspector.zig:143
|
||||||
|
msgid "Ghostty: Terminal Inspector"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/App.zig:1874
|
||||||
|
msgid "Menu"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/App.zig:1813 src/apprt/gtk/Window.zig:201
|
||||||
|
msgid "New Tab"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/App.zig:1812
|
||||||
|
msgid "New Window"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/App.zig:1825
|
||||||
|
msgid "Open Configuration"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/App.zig:1849 src/apprt/gtk/ClipboardConfirmationWindow.zig:169
|
||||||
|
msgid "Paste"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ClipboardConfirmationWindow.zig:245
|
||||||
|
msgid ""
|
||||||
|
"Pasting this text into the terminal may be dangerous as it looks like some commands may be executed.\n"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/App.zig:1826
|
||||||
|
msgid "Reload Configuration"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/App.zig:1864
|
||||||
|
msgid "Reset"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/App.zig:1816 src/apprt/gtk/App.zig:1857
|
||||||
|
msgid "Split Down"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/App.zig:1815 src/apprt/gtk/App.zig:1856
|
||||||
|
msgid "Split Right"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/App.zig:1824 src/apprt/gtk/App.zig:1865
|
||||||
|
msgid "Terminal Inspector"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:732
|
||||||
|
msgid ""
|
||||||
|
"There is still a running process in the terminal. Closing the terminal will kill this process.\n"
|
||||||
|
"Are you sure you want to close the terminal?\n"
|
||||||
|
"\n"
|
||||||
|
"Click 'No' to cancel and return to your terminal.\n"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Window.zig:174
|
||||||
|
msgid "View Open Tabs"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ClipboardConfirmationWindow.zig:236
|
||||||
|
msgid "Warning: Potentially Unsafe Paste"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ResizeOverlay.zig:107
|
||||||
|
msgid "c"
|
||||||
|
msgid_plural "c"
|
||||||
|
msgstr[0] ""
|
||||||
|
msgstr[1] ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ResizeOverlay.zig:111
|
||||||
|
msgid "r"
|
||||||
|
msgid_plural "r"
|
||||||
|
msgstr[0] ""
|
||||||
|
msgstr[1] ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Window.zig:220
|
||||||
|
msgid "⚠️ You're running a debug build of Ghostty! Performance will be degraded."
|
||||||
|
msgstr ""
|
@ -38,6 +38,7 @@ const inspector = @import("inspector.zig");
|
|||||||
const key = @import("key.zig");
|
const key = @import("key.zig");
|
||||||
const winproto = @import("winproto.zig");
|
const winproto = @import("winproto.zig");
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
|
const intl = @import("intl");
|
||||||
|
|
||||||
const log = std.log.scoped(.gtk);
|
const log = std.log.scoped(.gtk);
|
||||||
|
|
||||||
@ -1809,22 +1810,22 @@ fn initMenuContent(menu: *c.GMenu) void {
|
|||||||
const section = c.g_menu_new();
|
const section = c.g_menu_new();
|
||||||
defer c.g_object_unref(section);
|
defer c.g_object_unref(section);
|
||||||
c.g_menu_append_section(menu, null, @ptrCast(@alignCast(section)));
|
c.g_menu_append_section(menu, null, @ptrCast(@alignCast(section)));
|
||||||
c.g_menu_append(section, "New Window", "win.new_window");
|
c.g_menu_append(section, intl._("New Window"), "win.new_window");
|
||||||
c.g_menu_append(section, "New Tab", "win.new_tab");
|
c.g_menu_append(section, intl._("New Tab"), "win.new_tab");
|
||||||
c.g_menu_append(section, "Close Tab", "win.close_tab");
|
c.g_menu_append(section, intl._("Close Tab"), "win.close_tab");
|
||||||
c.g_menu_append(section, "Split Right", "win.split_right");
|
c.g_menu_append(section, intl._("Split Right"), "win.split_right");
|
||||||
c.g_menu_append(section, "Split Down", "win.split_down");
|
c.g_menu_append(section, intl._("Split Down"), "win.split_down");
|
||||||
c.g_menu_append(section, "Close Window", "win.close");
|
c.g_menu_append(section, intl._("Close Window"), "win.close");
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const section = c.g_menu_new();
|
const section = c.g_menu_new();
|
||||||
defer c.g_object_unref(section);
|
defer c.g_object_unref(section);
|
||||||
c.g_menu_append_section(menu, null, @ptrCast(@alignCast(section)));
|
c.g_menu_append_section(menu, null, @ptrCast(@alignCast(section)));
|
||||||
c.g_menu_append(section, "Terminal Inspector", "win.toggle_inspector");
|
c.g_menu_append(section, intl._("Terminal Inspector"), "win.toggle_inspector");
|
||||||
c.g_menu_append(section, "Open Configuration", "app.open-config");
|
c.g_menu_append(section, intl._("Open Configuration"), "app.open-config");
|
||||||
c.g_menu_append(section, "Reload Configuration", "app.reload-config");
|
c.g_menu_append(section, intl._("Reload Configuration"), "app.reload-config");
|
||||||
c.g_menu_append(section, "About Ghostty", "win.about");
|
c.g_menu_append(section, intl._("About Ghostty"), "win.about");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1845,24 +1846,24 @@ fn initContextMenu(self: *App) void {
|
|||||||
const section = c.g_menu_new();
|
const section = c.g_menu_new();
|
||||||
defer c.g_object_unref(section);
|
defer c.g_object_unref(section);
|
||||||
c.g_menu_append_section(menu, null, @ptrCast(@alignCast(section)));
|
c.g_menu_append_section(menu, null, @ptrCast(@alignCast(section)));
|
||||||
c.g_menu_append(section, "Copy", "win.copy");
|
c.g_menu_append(section, intl._("Copy"), "win.copy");
|
||||||
c.g_menu_append(section, "Paste", "win.paste");
|
c.g_menu_append(section, intl._("Paste"), "win.paste");
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const section = c.g_menu_new();
|
const section = c.g_menu_new();
|
||||||
defer c.g_object_unref(section);
|
defer c.g_object_unref(section);
|
||||||
c.g_menu_append_section(menu, null, @ptrCast(@alignCast(section)));
|
c.g_menu_append_section(menu, null, @ptrCast(@alignCast(section)));
|
||||||
c.g_menu_append(section, "Split Right", "win.split_right");
|
c.g_menu_append(section, intl._("Split Right"), "win.split_right");
|
||||||
c.g_menu_append(section, "Split Down", "win.split_down");
|
c.g_menu_append(section, intl._("Split Down"), "win.split_down");
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const section = c.g_menu_new();
|
const section = c.g_menu_new();
|
||||||
defer c.g_object_unref(section);
|
defer c.g_object_unref(section);
|
||||||
c.g_menu_append_section(menu, null, @ptrCast(@alignCast(section)));
|
c.g_menu_append_section(menu, null, @ptrCast(@alignCast(section)));
|
||||||
c.g_menu_append(section, "Reset", "win.reset");
|
c.g_menu_append(section, intl._("Reset"), "win.reset");
|
||||||
c.g_menu_append(section, "Terminal Inspector", "win.toggle_inspector");
|
c.g_menu_append(section, intl._("Terminal Inspector"), "win.toggle_inspector");
|
||||||
}
|
}
|
||||||
|
|
||||||
const section = c.g_menu_new();
|
const section = c.g_menu_new();
|
||||||
@ -1871,7 +1872,7 @@ fn initContextMenu(self: *App) void {
|
|||||||
defer c.g_object_unref(submenu);
|
defer c.g_object_unref(submenu);
|
||||||
|
|
||||||
initMenuContent(@ptrCast(submenu));
|
initMenuContent(@ptrCast(submenu));
|
||||||
c.g_menu_append_submenu(section, "Menu", @ptrCast(@alignCast(submenu)));
|
c.g_menu_append_submenu(section, intl._("Menu"), @ptrCast(@alignCast(submenu)));
|
||||||
c.g_menu_append_section(menu, null, @ptrCast(@alignCast(section)));
|
c.g_menu_append_section(menu, null, @ptrCast(@alignCast(section)));
|
||||||
|
|
||||||
self.context_menu = menu;
|
self.context_menu = menu;
|
||||||
|
@ -9,6 +9,7 @@ const CoreSurface = @import("../../Surface.zig");
|
|||||||
const App = @import("App.zig");
|
const App = @import("App.zig");
|
||||||
const View = @import("View.zig");
|
const View = @import("View.zig");
|
||||||
const c = @import("c.zig").c;
|
const c = @import("c.zig").c;
|
||||||
|
const intl = @import("intl");
|
||||||
|
|
||||||
const log = std.log.scoped(.gtk);
|
const log = std.log.scoped(.gtk);
|
||||||
|
|
||||||
@ -166,8 +167,8 @@ const ButtonsView = struct {
|
|||||||
|
|
||||||
pub fn init(root: *ClipboardConfirmation) !ButtonsView {
|
pub fn init(root: *ClipboardConfirmation) !ButtonsView {
|
||||||
const cancel_text, const confirm_text = switch (root.pending_req) {
|
const cancel_text, const confirm_text = switch (root.pending_req) {
|
||||||
.paste => .{ "Cancel", "Paste" },
|
.paste => .{ intl._("Cancel"), intl._("Paste") },
|
||||||
.osc_52_read, .osc_52_write => .{ "Deny", "Allow" },
|
.osc_52_read, .osc_52_write => .{ intl._("Deny"), intl._("Allow") },
|
||||||
};
|
};
|
||||||
|
|
||||||
const cancel_button = c.gtk_button_new_with_label(cancel_text);
|
const cancel_button = c.gtk_button_new_with_label(cancel_text);
|
||||||
@ -233,8 +234,8 @@ const ButtonsView = struct {
|
|||||||
/// The title of the window, based on the reason the prompt is being shown.
|
/// The title of the window, based on the reason the prompt is being shown.
|
||||||
fn titleText(req: apprt.ClipboardRequest) [:0]const u8 {
|
fn titleText(req: apprt.ClipboardRequest) [:0]const u8 {
|
||||||
return switch (req) {
|
return switch (req) {
|
||||||
.paste => "Warning: Potentially Unsafe Paste",
|
.paste => intl._("Warning: Potentially Unsafe Paste"),
|
||||||
.osc_52_read, .osc_52_write => "Authorize Clipboard Access",
|
.osc_52_read, .osc_52_write => intl._("Authorize Clipboard Access"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,16 +243,16 @@ fn titleText(req: apprt.ClipboardRequest) [:0]const u8 {
|
|||||||
/// is being shown.
|
/// is being shown.
|
||||||
fn promptText(req: apprt.ClipboardRequest) [:0]const u8 {
|
fn promptText(req: apprt.ClipboardRequest) [:0]const u8 {
|
||||||
return switch (req) {
|
return switch (req) {
|
||||||
.paste =>
|
.paste => intl._(
|
||||||
\\Pasting this text into the terminal may be dangerous as it looks like some commands may be executed.
|
\\Pasting this text into the terminal may be dangerous as it looks like some commands may be executed.
|
||||||
,
|
),
|
||||||
.osc_52_read =>
|
.osc_52_read => intl._(
|
||||||
\\An application is attempting to read from the clipboard.
|
\\An application is attempting to read from the clipboard.
|
||||||
\\The current clipboard contents are shown below.
|
\\The current clipboard contents are shown below.
|
||||||
,
|
),
|
||||||
.osc_52_write =>
|
.osc_52_write => intl._(
|
||||||
\\An application is attempting to write to the clipboard.
|
\\An application is attempting to write to the clipboard.
|
||||||
\\The content to write is shown below.
|
\\The content to write is shown below.
|
||||||
,
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ const std = @import("std");
|
|||||||
const c = @import("c.zig").c;
|
const c = @import("c.zig").c;
|
||||||
const configpkg = @import("../../config.zig");
|
const configpkg = @import("../../config.zig");
|
||||||
const Surface = @import("Surface.zig");
|
const Surface = @import("Surface.zig");
|
||||||
|
const intl = @import("intl");
|
||||||
|
|
||||||
const log = std.log.scoped(.gtk);
|
const log = std.log.scoped(.gtk);
|
||||||
|
|
||||||
@ -95,13 +96,20 @@ fn gtkUpdate(ud: ?*anyopaque) callconv(.C) c.gboolean {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const grid_size = surface.core_surface.size.grid();
|
const grid_size = surface.core_surface.size.grid();
|
||||||
var buf: [32]u8 = undefined;
|
|
||||||
|
var buf: [64]u8 = undefined;
|
||||||
const text = std.fmt.bufPrintZ(
|
const text = std.fmt.bufPrintZ(
|
||||||
&buf,
|
&buf,
|
||||||
"{d}c ⨯ {d}r",
|
"{d}{s} ⨯ {d}{s}",
|
||||||
.{
|
.{
|
||||||
grid_size.columns,
|
grid_size.columns,
|
||||||
|
// Translators: the abbreviation for "column" (of a grid) in your language.
|
||||||
|
// If the abbreviation cannot be intuitively understood, use the full word.
|
||||||
|
intl.ngettext("c", "c", grid_size.columns),
|
||||||
grid_size.rows,
|
grid_size.rows,
|
||||||
|
// Translators: the abbreviation for "row" (of a grid) in your language.
|
||||||
|
// If the abbreviation cannot be intuitively understood, use the full word.
|
||||||
|
intl.ngettext("r", "r", grid_size.rows),
|
||||||
},
|
},
|
||||||
) catch |err| {
|
) catch |err| {
|
||||||
log.err("unable to format text: {}", .{err});
|
log.err("unable to format text: {}", .{err});
|
||||||
|
@ -25,6 +25,7 @@ const ResizeOverlay = @import("ResizeOverlay.zig");
|
|||||||
const inspector = @import("inspector.zig");
|
const inspector = @import("inspector.zig");
|
||||||
const gtk_key = @import("key.zig");
|
const gtk_key = @import("key.zig");
|
||||||
const c = @import("c.zig").c;
|
const c = @import("c.zig").c;
|
||||||
|
const intl = @import("intl");
|
||||||
|
|
||||||
const log = std.log.scoped(.gtk_surface);
|
const log = std.log.scoped(.gtk_surface);
|
||||||
|
|
||||||
@ -725,14 +726,16 @@ pub fn close(self: *Surface, processActive: bool) void {
|
|||||||
c.GTK_DIALOG_MODAL,
|
c.GTK_DIALOG_MODAL,
|
||||||
c.GTK_MESSAGE_QUESTION,
|
c.GTK_MESSAGE_QUESTION,
|
||||||
c.GTK_BUTTONS_YES_NO,
|
c.GTK_BUTTONS_YES_NO,
|
||||||
"Close this terminal?",
|
intl._("Close this terminal?"),
|
||||||
);
|
);
|
||||||
c.gtk_message_dialog_format_secondary_text(
|
c.gtk_message_dialog_format_secondary_text(
|
||||||
@ptrCast(alert),
|
@ptrCast(alert),
|
||||||
"There is still a running process in the terminal. " ++
|
intl._(
|
||||||
"Closing the terminal will kill this process. " ++
|
\\There is still a running process in the terminal. Closing the terminal will kill this process.
|
||||||
"Are you sure you want to close the terminal?\n\n" ++
|
\\Are you sure you want to close the terminal?
|
||||||
"Click 'No' to cancel and return to your terminal.",
|
\\
|
||||||
|
\\Click 'No' to cancel and return to your terminal.
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
// We want the "yes" to appear destructive.
|
// We want the "yes" to appear destructive.
|
||||||
@ -1136,7 +1139,7 @@ pub fn setClipboardString(
|
|||||||
self.app.config.@"app-notifications".@"clipboard-copy")
|
self.app.config.@"app-notifications".@"clipboard-copy")
|
||||||
{
|
{
|
||||||
if (self.container.window()) |window|
|
if (self.container.window()) |window|
|
||||||
window.sendToast("Copied to clipboard");
|
window.sendToast(intl._("Copied to clipboard"));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ const CoreSurface = @import("../../Surface.zig");
|
|||||||
const Surface = @import("Surface.zig");
|
const Surface = @import("Surface.zig");
|
||||||
const Window = @import("Window.zig");
|
const Window = @import("Window.zig");
|
||||||
const c = @import("c.zig").c;
|
const c = @import("c.zig").c;
|
||||||
|
const intl = @import("intl");
|
||||||
|
|
||||||
const log = std.log.scoped(.gtk);
|
const log = std.log.scoped(.gtk);
|
||||||
|
|
||||||
@ -140,11 +141,11 @@ pub fn closeWithConfirmation(tab: *Tab) void {
|
|||||||
c.GTK_DIALOG_MODAL,
|
c.GTK_DIALOG_MODAL,
|
||||||
c.GTK_MESSAGE_QUESTION,
|
c.GTK_MESSAGE_QUESTION,
|
||||||
c.GTK_BUTTONS_YES_NO,
|
c.GTK_BUTTONS_YES_NO,
|
||||||
"Close this tab?",
|
intl._("Close this tab?"),
|
||||||
);
|
);
|
||||||
c.gtk_message_dialog_format_secondary_text(
|
c.gtk_message_dialog_format_secondary_text(
|
||||||
@ptrCast(alert),
|
@ptrCast(alert),
|
||||||
"All terminal sessions in this tab will be terminated.",
|
intl._("All terminal sessions in this tab will be terminated."),
|
||||||
);
|
);
|
||||||
|
|
||||||
// We want the "yes" to appear destructive.
|
// We want the "yes" to appear destructive.
|
||||||
|
@ -26,6 +26,7 @@ const Notebook = @import("notebook.zig").Notebook;
|
|||||||
const HeaderBar = @import("headerbar.zig").HeaderBar;
|
const HeaderBar = @import("headerbar.zig").HeaderBar;
|
||||||
const version = @import("version.zig");
|
const version = @import("version.zig");
|
||||||
const winproto = @import("winproto.zig");
|
const winproto = @import("winproto.zig");
|
||||||
|
const intl = @import("intl");
|
||||||
|
|
||||||
const log = std.log.scoped(.gtk);
|
const log = std.log.scoped(.gtk);
|
||||||
|
|
||||||
@ -171,7 +172,7 @@ pub fn init(self: *Window, app: *App) !void {
|
|||||||
const btn = switch (app.config.@"gtk-tabs-location") {
|
const btn = switch (app.config.@"gtk-tabs-location") {
|
||||||
.top, .bottom, .left, .right => btn: {
|
.top, .bottom, .left, .right => btn: {
|
||||||
const btn = c.gtk_toggle_button_new();
|
const btn = c.gtk_toggle_button_new();
|
||||||
c.gtk_widget_set_tooltip_text(btn, "View Open Tabs");
|
c.gtk_widget_set_tooltip_text(btn, intl._("View Open Tabs"));
|
||||||
c.gtk_button_set_icon_name(@ptrCast(btn), "view-grid-symbolic");
|
c.gtk_button_set_icon_name(@ptrCast(btn), "view-grid-symbolic");
|
||||||
_ = c.g_object_bind_property(
|
_ = c.g_object_bind_property(
|
||||||
btn,
|
btn,
|
||||||
@ -198,7 +199,7 @@ pub fn init(self: *Window, app: *App) !void {
|
|||||||
|
|
||||||
{
|
{
|
||||||
const btn = c.gtk_button_new_from_icon_name("tab-new-symbolic");
|
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, intl._("New Tab"));
|
||||||
_ = c.g_signal_connect_data(btn, "clicked", c.G_CALLBACK(>kTabNewClick), self, null, c.G_CONNECT_DEFAULT);
|
_ = c.g_signal_connect_data(btn, "clicked", c.G_CALLBACK(>kTabNewClick), self, null, c.G_CONNECT_DEFAULT);
|
||||||
self.headerbar.packStart(btn);
|
self.headerbar.packStart(btn);
|
||||||
}
|
}
|
||||||
@ -217,7 +218,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.
|
// This is a really common issue where people build from source in debug and performance is really bad.
|
||||||
if (comptime std.debug.runtime_safety) {
|
if (comptime std.debug.runtime_safety) {
|
||||||
const warning_box = c.gtk_box_new(c.GTK_ORIENTATION_VERTICAL, 0);
|
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 = intl._("⚠️ You're running a debug build of Ghostty! Performance will be degraded.");
|
||||||
if ((comptime adwaita.versionAtLeast(1, 3, 0)) and
|
if ((comptime adwaita.versionAtLeast(1, 3, 0)) and
|
||||||
adwaita.enabled(&app.config) and
|
adwaita.enabled(&app.config) and
|
||||||
adwaita.versionAtLeast(1, 3, 0))
|
adwaita.versionAtLeast(1, 3, 0))
|
||||||
@ -793,11 +794,11 @@ fn gtkCloseRequest(v: *c.GtkWindow, ud: ?*anyopaque) callconv(.C) bool {
|
|||||||
c.GTK_DIALOG_MODAL,
|
c.GTK_DIALOG_MODAL,
|
||||||
c.GTK_MESSAGE_QUESTION,
|
c.GTK_MESSAGE_QUESTION,
|
||||||
c.GTK_BUTTONS_YES_NO,
|
c.GTK_BUTTONS_YES_NO,
|
||||||
"Close this window?",
|
intl._("Close this window?"),
|
||||||
);
|
);
|
||||||
c.gtk_message_dialog_format_secondary_text(
|
c.gtk_message_dialog_format_secondary_text(
|
||||||
@ptrCast(alert),
|
@ptrCast(alert),
|
||||||
"All terminal sessions in this window will be terminated.",
|
intl._("All terminal sessions in this window will be terminated."),
|
||||||
);
|
);
|
||||||
|
|
||||||
// We want the "yes" to appear destructive.
|
// We want the "yes" to appear destructive.
|
||||||
@ -896,7 +897,7 @@ fn gtkActionAbout(
|
|||||||
"application-name",
|
"application-name",
|
||||||
name,
|
name,
|
||||||
"developer-name",
|
"developer-name",
|
||||||
"Ghostty Developers",
|
intl._("Ghostty Developers").ptr,
|
||||||
"application-icon",
|
"application-icon",
|
||||||
icon,
|
icon,
|
||||||
"version",
|
"version",
|
||||||
@ -915,7 +916,7 @@ fn gtkActionAbout(
|
|||||||
"logo-icon-name",
|
"logo-icon-name",
|
||||||
icon,
|
icon,
|
||||||
"title",
|
"title",
|
||||||
"About Ghostty",
|
intl._("About Ghostty").ptr,
|
||||||
"version",
|
"version",
|
||||||
build_config.version_string.ptr,
|
build_config.version_string.ptr,
|
||||||
"website",
|
"website",
|
||||||
|
@ -9,6 +9,7 @@ const TerminalWindow = @import("Window.zig");
|
|||||||
const ImguiWidget = @import("ImguiWidget.zig");
|
const ImguiWidget = @import("ImguiWidget.zig");
|
||||||
const c = @import("c.zig").c;
|
const c = @import("c.zig").c;
|
||||||
const CoreInspector = @import("../../inspector/main.zig").Inspector;
|
const CoreInspector = @import("../../inspector/main.zig").Inspector;
|
||||||
|
const intl = @import("intl");
|
||||||
|
|
||||||
const log = std.log.scoped(.inspector);
|
const log = std.log.scoped(.inspector);
|
||||||
|
|
||||||
@ -140,7 +141,7 @@ const Window = struct {
|
|||||||
const gtk_window: *c.GtkWindow = @ptrCast(window);
|
const gtk_window: *c.GtkWindow = @ptrCast(window);
|
||||||
errdefer c.gtk_window_destroy(gtk_window);
|
errdefer c.gtk_window_destroy(gtk_window);
|
||||||
self.window = gtk_window;
|
self.window = gtk_window;
|
||||||
c.gtk_window_set_title(gtk_window, "Ghostty: Terminal Inspector");
|
c.gtk_window_set_title(gtk_window, intl._("Ghostty: Terminal Inspector"));
|
||||||
c.gtk_window_set_default_size(gtk_window, 1000, 600);
|
c.gtk_window_set_default_size(gtk_window, 1000, 600);
|
||||||
c.gtk_window_set_icon_name(gtk_window, build_config.bundle_id);
|
c.gtk_window_set_icon_name(gtk_window, build_config.bundle_id);
|
||||||
c.gtk_widget_add_css_class(@ptrCast(@alignCast(gtk_window)), "window");
|
c.gtk_widget_add_css_class(@ptrCast(@alignCast(gtk_window)), "window");
|
||||||
|
@ -14,6 +14,64 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyResources {
|
|||||||
var steps = std.ArrayList(*std.Build.Step).init(b.allocator);
|
var steps = std.ArrayList(*std.Build.Step).init(b.allocator);
|
||||||
errdefer steps.deinit();
|
errdefer steps.deinit();
|
||||||
|
|
||||||
|
// Localization files (.pot, .po, .mo)
|
||||||
|
{
|
||||||
|
const update = b.step("update-translations", "Update translation files");
|
||||||
|
|
||||||
|
const gettext = b.dependency("zig_gettext", .{
|
||||||
|
// We're running this on the host, so we need to compile it for the host
|
||||||
|
.target = b.graph.host,
|
||||||
|
.optimize = cfg.optimize,
|
||||||
|
});
|
||||||
|
|
||||||
|
const xgettext = b.addRunArtifact(gettext.artifact("xgettext"));
|
||||||
|
const pot = pot: {
|
||||||
|
var src_files = try b.build_root.handle.openDir("src", .{ .iterate = true });
|
||||||
|
defer src_files.close();
|
||||||
|
|
||||||
|
var walk = try src_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.addFileArg(b.path(b.pathJoin(&.{ "src", src.path })));
|
||||||
|
}
|
||||||
|
break :pot xgettext.captureStdOut();
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Use UpdateSourceFiles when Zig 0.14 releases
|
||||||
|
var wf_update = b.addWriteFiles();
|
||||||
|
wf_update.addCopyFileToSource(pot, "po/messages.pot");
|
||||||
|
update.dependOn(&wf_update.step);
|
||||||
|
|
||||||
|
var wf_mo = b.addWriteFiles();
|
||||||
|
var linguas = try b.build_root.handle.openFile("po/LINGUAS", .{});
|
||||||
|
defer linguas.close();
|
||||||
|
var reader = linguas.reader();
|
||||||
|
var buf: [64]u8 = undefined;
|
||||||
|
|
||||||
|
while (try reader.readUntilDelimiterOrEof(&buf, '\n')) |locale| {
|
||||||
|
const po = b.fmt("po/{s}.po", .{locale});
|
||||||
|
|
||||||
|
const mo = b.addRunArtifact(gettext.artifact("msgfmt"));
|
||||||
|
mo.addFileArg(b.path(po));
|
||||||
|
_ = wf_mo.addCopyFile(
|
||||||
|
mo.captureStdOut(),
|
||||||
|
b.pathJoin(&.{ "share", "locale", locale, "LC_MESSAGES", "messages.mo" }),
|
||||||
|
);
|
||||||
|
|
||||||
|
const msgmerge = b.addSystemCommand(&.{ "msgmerge", "--update", "--quiet" });
|
||||||
|
msgmerge.addFileArg(b.path(po));
|
||||||
|
msgmerge.addFileArg(pot);
|
||||||
|
update.dependOn(&msgmerge.step);
|
||||||
|
}
|
||||||
|
|
||||||
|
try steps.append(&wf_mo.step);
|
||||||
|
}
|
||||||
|
|
||||||
// Terminfo
|
// Terminfo
|
||||||
terminfo: {
|
terminfo: {
|
||||||
// Encode our terminfo
|
// Encode our terminfo
|
||||||
|
@ -358,6 +358,10 @@ pub fn add(
|
|||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
.with_tui = false,
|
.with_tui = false,
|
||||||
}).module("zf"));
|
}).module("zf"));
|
||||||
|
step.root_module.addImport("intl", b.dependency("libintl", .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
}).module("intl"));
|
||||||
|
|
||||||
// Mac Stuff
|
// Mac Stuff
|
||||||
if (step.rootModuleTarget().isDarwin()) {
|
if (step.rootModuleTarget().isDarwin()) {
|
||||||
|
@ -10,6 +10,7 @@ const oni = @import("oniguruma");
|
|||||||
const crash = @import("crash/main.zig");
|
const crash = @import("crash/main.zig");
|
||||||
const renderer = @import("renderer.zig");
|
const renderer = @import("renderer.zig");
|
||||||
const xev = @import("xev");
|
const xev = @import("xev");
|
||||||
|
const intl = @import("intl");
|
||||||
|
|
||||||
/// Global process state. This is initialized in main() for exe artifacts
|
/// Global process state. This is initialized in main() for exe artifacts
|
||||||
/// and by ghostty_init() for lib artifacts. This should ONLY be used by
|
/// and by ghostty_init() for lib artifacts. This should ONLY be used by
|
||||||
@ -162,6 +163,8 @@ pub const GlobalState = struct {
|
|||||||
// hereafter can use this cached value.
|
// hereafter can use this cached value.
|
||||||
self.resources_dir = try internal_os.resourcesDir(self.alloc);
|
self.resources_dir = try internal_os.resourcesDir(self.alloc);
|
||||||
errdefer if (self.resources_dir) |dir| self.alloc.free(dir);
|
errdefer if (self.resources_dir) |dir| self.alloc.free(dir);
|
||||||
|
|
||||||
|
try self.initI18n();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cleans up the global state. This doesn't _need_ to be called but
|
/// Cleans up the global state. This doesn't _need_ to be called but
|
||||||
@ -200,6 +203,20 @@ pub const GlobalState = struct {
|
|||||||
std.log.warn("failed to ignore SIGPIPE err={}", .{err});
|
std.log.warn("failed to ignore SIGPIPE err={}", .{err});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
fn initI18n(self: *GlobalState) std.mem.Allocator.Error!void {
|
||||||
|
const resources = self.resources_dir orelse {
|
||||||
|
std.log.warn("resources dir not found: not localizing", .{});
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
const share = std.fs.path.dirname(resources) orelse return;
|
||||||
|
const locale = try std.fs.path.joinZ(self.alloc, &.{ share, "locale" });
|
||||||
|
defer self.alloc.free(locale);
|
||||||
|
|
||||||
|
std.log.warn("locale={s}", .{locale});
|
||||||
|
|
||||||
|
try intl.bindTextDomain("messages", locale);
|
||||||
|
try intl.setTextDomain("messages");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Maintains the Unix resource limits that we set for our process. This
|
/// Maintains the Unix resource limits that we set for our process. This
|
||||||
|
@ -9,14 +9,13 @@ const Allocator = std.mem.Allocator;
|
|||||||
/// This is highly Ghostty-specific and can likely be generalized at
|
/// This is highly Ghostty-specific and can likely be generalized at
|
||||||
/// some point but we can cross that bridge if we ever need to.
|
/// some point but we can cross that bridge if we ever need to.
|
||||||
pub fn resourcesDir(alloc: std.mem.Allocator) !?[]const u8 {
|
pub fn resourcesDir(alloc: std.mem.Allocator) !?[]const u8 {
|
||||||
// If we have an environment variable set, we always use that.
|
// If we have an environment variable set, we prefer that *only* in release mode.
|
||||||
// Note: we ALWAYS want to allocate here because the result is always
|
//
|
||||||
// freed, do not try to use internal_os.getenv or posix getenv.
|
// The reason is that debug builds built by developers may have updated
|
||||||
if (std.process.getEnvVarOwned(alloc, "GHOSTTY_RESOURCES_DIR")) |dir| {
|
// resources, and debug Ghostty launched from release Ghostty should not
|
||||||
if (dir.len > 0) return dir;
|
// inherit old/stale resources of release Ghostty.
|
||||||
} else |err| switch (err) {
|
if (comptime builtin.mode != .Debug) {
|
||||||
error.EnvironmentVariableNotFound => {},
|
if (try getDirFromEnv(alloc)) |dir| return dir;
|
||||||
else => return err,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is the sentinel value we look for in the path to know
|
// This is the sentinel value we look for in the path to know
|
||||||
@ -52,6 +51,25 @@ pub fn resourcesDir(alloc: std.mem.Allocator) !?[]const u8 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we are in debug mode and we couldn't find freshly-built
|
||||||
|
// resources for some reason, we fall back to using the env var
|
||||||
|
if (comptime builtin.mode == .Debug) {
|
||||||
|
if (try getDirFromEnv(alloc)) |dir| return dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getDirFromEnv(alloc: Allocator) !?[]u8 {
|
||||||
|
// Note: we ALWAYS want to allocate here because the result is always
|
||||||
|
// freed, do not try to use internal_os.getenv or posix getenv.
|
||||||
|
if (std.process.getEnvVarOwned(alloc, "GHOSTTY_RESOURCES_DIR")) |dir| {
|
||||||
|
if (dir.len > 0) return dir;
|
||||||
|
} else |err| switch (err) {
|
||||||
|
error.EnvironmentVariableNotFound => {},
|
||||||
|
else => return err,
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user