apprt/gtk: use the new global i18n API

This commit is contained in:
Mitchell Hashimoto
2025-03-07 10:41:22 -08:00
parent cff092f4c6
commit c7681e8fd7
5 changed files with 15 additions and 45 deletions

View File

@ -40,7 +40,6 @@ const ClipboardConfirmationWindow = @import("ClipboardConfirmationWindow.zig");
const CloseDialog = @import("CloseDialog.zig"); const CloseDialog = @import("CloseDialog.zig");
const Split = @import("Split.zig"); const Split = @import("Split.zig");
const c = @import("c.zig").c; const c = @import("c.zig").c;
const i18n = @import("i18n.zig");
const version = @import("version.zig"); const version = @import("version.zig");
const inspector = @import("inspector.zig"); const inspector = @import("inspector.zig");
const key = @import("key.zig"); const key = @import("key.zig");
@ -101,11 +100,6 @@ quit_timer: union(enum) {
pub fn init(core_app: *CoreApp, opts: Options) !App { pub fn init(core_app: *CoreApp, opts: Options) !App {
_ = opts; _ = 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 our GTK version
log.info("GTK version build={d}.{d}.{d} runtime={d}.{d}.{d}", .{ log.info("GTK version build={d}.{d}.{d} runtime={d}.{d}.{d}", .{
c.GTK_MAJOR_VERSION, c.GTK_MAJOR_VERSION,
@ -124,6 +118,10 @@ pub fn init(core_app: *CoreApp, opts: Options) !App {
c.adw_get_micro_version(), 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 // Load our configuration
var config = try Config.load(core_app.alloc); var config = try Config.load(core_app.alloc);
errdefer config.deinit(); errdefer config.deinit();

View File

@ -16,6 +16,7 @@ const build_options = @import("build_options");
const configpkg = @import("../../config.zig"); const configpkg = @import("../../config.zig");
const apprt = @import("../../apprt.zig"); const apprt = @import("../../apprt.zig");
const font = @import("../../font/main.zig"); const font = @import("../../font/main.zig");
const i18n = @import("../../os/main.zig").i18n;
const input = @import("../../input.zig"); const input = @import("../../input.zig");
const renderer = @import("../../renderer.zig"); const renderer = @import("../../renderer.zig");
const terminal = @import("../../terminal/main.zig"); const terminal = @import("../../terminal/main.zig");
@ -36,7 +37,6 @@ const gtk_key = @import("key.zig");
const c = @import("c.zig").c; const c = @import("c.zig").c;
const Builder = @import("Builder.zig"); const Builder = @import("Builder.zig");
const adwaita = @import("adwaita.zig"); const adwaita = @import("adwaita.zig");
const i18n = @import("i18n.zig");
const log = std.log.scoped(.gtk_surface); const log = std.log.scoped(.gtk_surface);

View File

@ -18,6 +18,7 @@ const gtk = @import("gtk");
const build_config = @import("../../build_config.zig"); const build_config = @import("../../build_config.zig");
const configpkg = @import("../../config.zig"); const configpkg = @import("../../config.zig");
const font = @import("../../font/main.zig"); const font = @import("../../font/main.zig");
const i18n = @import("../../os/main.zig").i18n;
const input = @import("../../input.zig"); const input = @import("../../input.zig");
const CoreSurface = @import("../../Surface.zig"); const CoreSurface = @import("../../Surface.zig");
@ -34,7 +35,6 @@ const HeaderBar = @import("headerbar.zig");
const CloseDialog = @import("CloseDialog.zig"); const CloseDialog = @import("CloseDialog.zig");
const version = @import("version.zig"); const version = @import("version.zig");
const winproto = @import("winproto.zig"); const winproto = @import("winproto.zig");
const i18n = @import("i18n.zig");
const log = std.log.scoped(.gtk); const log = std.log.scoped(.gtk);

View File

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

View File

@ -63,6 +63,15 @@ pub fn init(resources_dir: []const u8) InitError!void {
return error.OutOfMemory; 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. /// Finds the closest matching locale for a given language code.
pub fn closestLocaleForLanguage(lang: []const u8) ?[:0]const u8 { pub fn closestLocaleForLanguage(lang: []const u8) ?[:0]const u8 {
for (locales) |locale| { for (locales) |locale| {