diff --git a/src/apprt/gtk/App.zig b/src/apprt/gtk/App.zig index 84df35606..9893f1ee9 100644 --- a/src/apprt/gtk/App.zig +++ b/src/apprt/gtk/App.zig @@ -40,7 +40,6 @@ const ClipboardConfirmationWindow = @import("ClipboardConfirmationWindow.zig"); const CloseDialog = @import("CloseDialog.zig"); const Split = @import("Split.zig"); const c = @import("c.zig").c; -const i18n = @import("i18n.zig"); const version = @import("version.zig"); const inspector = @import("inspector.zig"); const key = @import("key.zig"); @@ -101,11 +100,6 @@ quit_timer: union(enum) { pub fn init(core_app: *CoreApp, opts: Options) !App { _ = opts; - // This can technically be placed *anywhere* because we don't have any - // localized log messages. It just has to be placed before any localized - // widgets are drawn. - try i18n.init(core_app.alloc); - // Log our GTK version log.info("GTK version build={d}.{d}.{d} runtime={d}.{d}.{d}", .{ c.GTK_MAJOR_VERSION, @@ -124,6 +118,10 @@ pub fn init(core_app: *CoreApp, opts: Options) !App { c.adw_get_micro_version(), }); + // Set gettext global domain to be our app so that our unqualified + // translations map to our translations. + try internal_os.i18n.initGlobalDomain(); + // Load our configuration var config = try Config.load(core_app.alloc); errdefer config.deinit(); diff --git a/src/apprt/gtk/Surface.zig b/src/apprt/gtk/Surface.zig index ae3ca12d6..23abccc20 100644 --- a/src/apprt/gtk/Surface.zig +++ b/src/apprt/gtk/Surface.zig @@ -16,6 +16,7 @@ const build_options = @import("build_options"); const configpkg = @import("../../config.zig"); const apprt = @import("../../apprt.zig"); const font = @import("../../font/main.zig"); +const i18n = @import("../../os/main.zig").i18n; const input = @import("../../input.zig"); const renderer = @import("../../renderer.zig"); const terminal = @import("../../terminal/main.zig"); @@ -36,7 +37,6 @@ 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); diff --git a/src/apprt/gtk/Window.zig b/src/apprt/gtk/Window.zig index 0e0f71662..8c3e135c5 100644 --- a/src/apprt/gtk/Window.zig +++ b/src/apprt/gtk/Window.zig @@ -18,6 +18,7 @@ const gtk = @import("gtk"); const build_config = @import("../../build_config.zig"); const configpkg = @import("../../config.zig"); const font = @import("../../font/main.zig"); +const i18n = @import("../../os/main.zig").i18n; const input = @import("../../input.zig"); const CoreSurface = @import("../../Surface.zig"); @@ -34,7 +35,6 @@ const HeaderBar = @import("headerbar.zig"); const CloseDialog = @import("CloseDialog.zig"); const version = @import("version.zig"); const winproto = @import("winproto.zig"); -const i18n = @import("i18n.zig"); const log = std.log.scoped(.gtk); diff --git a/src/apprt/gtk/i18n.zig b/src/apprt/gtk/i18n.zig deleted file mode 100644 index 630d150a6..000000000 --- a/src/apprt/gtk/i18n.zig +++ /dev/null @@ -1,37 +0,0 @@ -//! I18n support for the GTK frontend based on gettext/libintl -//! -//! This is normally built into the C standard library for the *vast* majority -//! of users who use glibc, but for musl users we fall back to the `gettext-tiny` -//! stub implementation which provides all of the necessary interfaces. -//! Musl users who do want to use localization should know what they need to do. - -const std = @import("std"); -const global = &@import("../../global.zig").state; -const build_config = @import("../../build_config.zig"); - -const log = std.log.scoped(.gtk_i18n); - -pub fn init(alloc: std.mem.Allocator) !void { - const resources_dir = global.resources_dir orelse { - log.warn("resource dir not found; not localizing", .{}); - return; - }; - const share_dir = std.fs.path.dirname(resources_dir) orelse { - log.warn("resource dir not placed in a share/ directory; not localizing", .{}); - return; - }; - - const locale_dir = try std.fs.path.joinZ(alloc, &.{ share_dir, "locale" }); - defer alloc.free(locale_dir); - - // The only way these calls can fail is if we're out of memory - _ = bindtextdomain(build_config.bundle_id, locale_dir.ptr) orelse return error.OutOfMemory; - _ = textdomain(build_config.bundle_id) orelse return error.OutOfMemory; -} - -// Manually include function definitions for the gettext functions -// 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/os/i18n.zig b/src/os/i18n.zig index 15255578a..8a4efdc73 100644 --- a/src/os/i18n.zig +++ b/src/os/i18n.zig @@ -63,6 +63,15 @@ pub fn init(resources_dir: []const u8) InitError!void { return error.OutOfMemory; } +/// Set the global gettext domain to our bundle ID, allowing unqualified +/// `gettext` (`_`) calls to look up translations for our application. +/// +/// This should only be called for apprts that are fully owning the +/// Ghostty application. This should not be called for libghostty users. +pub fn initGlobalDomain() error{OutOfMemory}!void { + _ = textdomain(build_config.bundle_id) orelse return error.OutOfMemory; +} + /// Finds the closest matching locale for a given language code. pub fn closestLocaleForLanguage(lang: []const u8) ?[:0]const u8 { for (locales) |locale| {