mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-04-19 05:50:27 +00:00
gtk: add localization support, take 3 (#6004)
This is my third (!) attempt at implementing localization support. By leveraging GTK builder to do most of the `gettext` calls, I can avoid the whole mess about missing symbols on non-glibc platforms. Added some documentation too for contributors and translators, just for good measure. Supersedes #5214, resolves the GTK half of #2357
This commit is contained in:
118
src/build/GhosttyI18n.zig
Normal file
118
src/build/GhosttyI18n.zig
Normal file
@@ -0,0 +1,118 @@
|
||||
const GhosttyI18n = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const Config = @import("Config.zig");
|
||||
const gresource = @import("../apprt/gtk/gresource.zig");
|
||||
|
||||
const domain = "com.mitchellh.ghostty";
|
||||
|
||||
const locales = [_][]const u8{
|
||||
"zh_CN.UTF-8",
|
||||
};
|
||||
|
||||
owner: *std.Build,
|
||||
steps: []*std.Build.Step,
|
||||
|
||||
/// This step updates the translation files on disk that should be
|
||||
/// committed to the repo.
|
||||
update_step: *std.Build.Step,
|
||||
|
||||
pub fn init(b: *std.Build, cfg: *const Config) !GhosttyI18n {
|
||||
var steps = std.ArrayList(*std.Build.Step).init(b.allocator);
|
||||
defer steps.deinit();
|
||||
|
||||
if (cfg.app_runtime == .gtk) {
|
||||
// Output the .mo files used by the GTK apprt
|
||||
inline for (locales) |locale| {
|
||||
const msgfmt = b.addSystemCommand(&.{ "msgfmt", "-o", "-" });
|
||||
msgfmt.addFileArg(b.path("po/" ++ locale ++ ".po"));
|
||||
|
||||
try steps.append(&b.addInstallFile(
|
||||
msgfmt.captureStdOut(),
|
||||
std.fmt.comptimePrint(
|
||||
"share/locale/{s}/LC_MESSAGES/{s}.mo",
|
||||
.{ locale, domain },
|
||||
),
|
||||
).step);
|
||||
}
|
||||
}
|
||||
|
||||
return .{
|
||||
.owner = b,
|
||||
.update_step = try createUpdateStep(b),
|
||||
.steps = try steps.toOwnedSlice(),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn install(self: *const GhosttyI18n) void {
|
||||
for (self.steps) |step| self.owner.getInstallStep().dependOn(step);
|
||||
}
|
||||
|
||||
fn createUpdateStep(b: *std.Build) !*std.Build.Step {
|
||||
const xgettext = b.addSystemCommand(&.{
|
||||
"xgettext",
|
||||
"--language=C", // Silence the "unknown extension" errors
|
||||
"--from-code=UTF-8",
|
||||
"--add-comments=Translators",
|
||||
"--keyword=_",
|
||||
"--keyword=C_:1c,2",
|
||||
"--package-name=" ++ domain,
|
||||
"--msgid-bugs-address=m@mitchellh.com",
|
||||
"--copyright-holder=Mitchell Hashimoto",
|
||||
"-o",
|
||||
"-",
|
||||
});
|
||||
|
||||
// Not cacheable due to the gresource files
|
||||
xgettext.has_side_effects = true;
|
||||
|
||||
inline for (gresource.blueprint_files) |blp| {
|
||||
// We avoid using addFileArg here since the full, absolute file path
|
||||
// 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.
|
||||
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 })));
|
||||
}
|
||||
}
|
||||
|
||||
const wf = b.addWriteFiles();
|
||||
wf.addCopyFileToSource(
|
||||
xgettext.captureStdOut(),
|
||||
"po/" ++ domain ++ ".pot",
|
||||
);
|
||||
|
||||
inline for (locales) |locale| {
|
||||
const msgmerge = b.addSystemCommand(&.{ "msgmerge", "-q" });
|
||||
msgmerge.addFileArg(b.path("po/" ++ locale ++ ".po"));
|
||||
msgmerge.addFileArg(xgettext.captureStdOut());
|
||||
wf.addCopyFileToSource(msgmerge.captureStdOut(), "po/" ++ locale ++ ".po");
|
||||
}
|
||||
|
||||
return &wf.step;
|
||||
}
|
||||
@@ -40,6 +40,7 @@ COPY ./dist/linux /src/dist/linux
|
||||
COPY ./images /src/images
|
||||
COPY ./include /src/include
|
||||
COPY ./pkg /src/pkg
|
||||
COPY ./po /src/po
|
||||
COPY ./nix /src/nix
|
||||
COPY ./vendor /src/vendor
|
||||
COPY ./build.zig /src/build.zig
|
||||
|
||||
@@ -13,6 +13,7 @@ pub const GhosttyExe = @import("GhosttyExe.zig");
|
||||
pub const GhosttyFrameData = @import("GhosttyFrameData.zig");
|
||||
pub const GhosttyLib = @import("GhosttyLib.zig");
|
||||
pub const GhosttyResources = @import("GhosttyResources.zig");
|
||||
pub const GhosttyI18n = @import("GhosttyI18n.zig");
|
||||
pub const GhosttyXCFramework = @import("GhosttyXCFramework.zig");
|
||||
pub const GhosttyWebdata = @import("GhosttyWebdata.zig");
|
||||
pub const HelpStrings = @import("HelpStrings.zig");
|
||||
|
||||
Reference in New Issue
Block a user