diff --git a/include/ghostty.h b/include/ghostty.h index 4fc180a1a..2dc1bffef 100644 --- a/include/ghostty.h +++ b/include/ghostty.h @@ -669,6 +669,7 @@ typedef struct { int ghostty_init(void); void ghostty_cli_main(uintptr_t, char**); ghostty_info_s ghostty_info(void); +const char* ghostty_translate(const char*); ghostty_config_t ghostty_config_new(); void ghostty_config_free(ghostty_config_t); diff --git a/macos/Ghostty.xcodeproj/project.pbxproj b/macos/Ghostty.xcodeproj/project.pbxproj index 0c68da534..b4c00946c 100644 --- a/macos/Ghostty.xcodeproj/project.pbxproj +++ b/macos/Ghostty.xcodeproj/project.pbxproj @@ -40,6 +40,7 @@ A53D0C952B53B4D800305CE6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A5B30538299BEAAB0047F10C /* Assets.xcassets */; }; A53D0C9B2B543F3B00305CE6 /* Ghostty.App.swift in Sources */ = {isa = PBXBuildFile; fileRef = A53D0C992B543F3B00305CE6 /* Ghostty.App.swift */; }; A53D0C9C2B543F7B00305CE6 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = A55B7BB729B6F53A0055DE60 /* Package.swift */; }; + A546F1142D7B68D7003B11A0 /* locale in Resources */ = {isa = PBXBuildFile; fileRef = A546F1132D7B68D7003B11A0 /* locale */; }; A54B0CE92D0CECD100CBEFF8 /* ColorizedGhosttyIconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A54B0CE82D0CECD100CBEFF8 /* ColorizedGhosttyIconView.swift */; }; A54B0CEB2D0CFB4C00CBEFF8 /* NSImage+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A54B0CEA2D0CFB4A00CBEFF8 /* NSImage+Extension.swift */; }; A54B0CED2D0CFB7700CBEFF8 /* ColorizedGhosttyIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = A54B0CEC2D0CFB7300CBEFF8 /* ColorizedGhosttyIcon.swift */; }; @@ -138,6 +139,7 @@ A53A6C022CCC1B7D00943E98 /* Ghostty.Action.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ghostty.Action.swift; sourceTree = ""; }; A53D0C932B53B43700305CE6 /* iOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSApp.swift; sourceTree = ""; }; A53D0C992B543F3B00305CE6 /* Ghostty.App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ghostty.App.swift; sourceTree = ""; }; + A546F1132D7B68D7003B11A0 /* locale */ = {isa = PBXFileReference; lastKnownFileType = folder; name = locale; path = "../zig-out/share/locale"; sourceTree = ""; }; A54B0CE82D0CECD100CBEFF8 /* ColorizedGhosttyIconView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorizedGhosttyIconView.swift; sourceTree = ""; }; A54B0CEA2D0CFB4A00CBEFF8 /* NSImage+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSImage+Extension.swift"; sourceTree = ""; }; A54B0CEC2D0CFB7300CBEFF8 /* ColorizedGhosttyIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorizedGhosttyIcon.swift; sourceTree = ""; }; @@ -424,6 +426,7 @@ 29C15B1C2CDC3B2000520DD4 /* bat */, A586167B2B7703CC009BDB1D /* fish */, 55154BDF2B33911F001622DC /* ghostty */, + A546F1132D7B68D7003B11A0 /* locale */, A5985CE52C33060F00C57AD3 /* man */, 9351BE8E2D22937F003B3499 /* nvim */, A5A1F8842A489D6800D1E8BC /* terminfo */, @@ -593,20 +596,21 @@ buildActionMask = 2147483647; files = ( FC9ABA9C2D0F53F80020D4C8 /* bash-completion in Resources */, + 29C15B1D2CDC3B2900520DD4 /* bat in Resources */, + A586167C2B7703CC009BDB1D /* fish in Resources */, + 55154BE02B33911F001622DC /* ghostty in Resources */, + A546F1142D7B68D7003B11A0 /* locale in Resources */, + A5985CE62C33060F00C57AD3 /* man in Resources */, + 9351BE8E3D22937F003B3499 /* nvim in Resources */, + A5A1F8852A489D6800D1E8BC /* terminfo in Resources */, + 552964E62B34A9B400030505 /* vim in Resources */, + FC5218FA2D10FFCE004C93E0 /* zsh in Resources */, A5B30539299BEAAB0047F10C /* Assets.xcassets in Resources */, A51BFC1E2B2FB5CE00E92F16 /* About.xib in Resources */, A5E112932AF73E6E00C6E0C2 /* ClipboardConfirmation.xib in Resources */, A5CDF1912AAF9A5800513312 /* ConfigurationErrors.xib in Resources */, 857F63812A5E64F200CA4815 /* MainMenu.xib in Resources */, - 29C15B1D2CDC3B2900520DD4 /* bat in Resources */, A596309A2AEE1C6400D64628 /* Terminal.xib in Resources */, - A586167C2B7703CC009BDB1D /* fish in Resources */, - FC5218FA2D10FFCE004C93E0 /* zsh in Resources */, - 55154BE02B33911F001622DC /* ghostty in Resources */, - A5985CE62C33060F00C57AD3 /* man in Resources */, - A5A1F8852A489D6800D1E8BC /* terminfo in Resources */, - 552964E62B34A9B400030505 /* vim in Resources */, - 9351BE8E3D22937F003B3499 /* nvim in Resources */, A5CBD05C2CA0C5C70017A1AE /* QuickTerminal.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/macos/Ghostty.xcodeproj/xcshareddata/xcschemes/Ghostty.xcscheme b/macos/Ghostty.xcodeproj/xcshareddata/xcschemes/Ghostty.xcscheme index 5900042f2..c2e61f1c2 100644 --- a/macos/Ghostty.xcodeproj/xcshareddata/xcschemes/Ghostty.xcscheme +++ b/macos/Ghostty.xcodeproj/xcshareddata/xcschemes/Ghostty.xcscheme @@ -33,6 +33,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "zh-Hans" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/src/build/GhosttyI18n.zig b/src/build/GhosttyI18n.zig index b7aa0be11..56848fdc3 100644 --- a/src/build/GhosttyI18n.zig +++ b/src/build/GhosttyI18n.zig @@ -3,13 +3,10 @@ const GhosttyI18n = @This(); const std = @import("std"); const Config = @import("Config.zig"); const gresource = @import("../apprt/gtk/gresource.zig"); +const internal_os = @import("../os/main.zig"); const domain = "com.mitchellh.ghostty"; -const locales = [_][]const u8{ - "zh_CN.UTF-8", -}; - owner: *std.Build, steps: []*std.Build.Step, @@ -23,7 +20,7 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyI18n { var steps = std.ArrayList(*std.Build.Step).init(b.allocator); defer steps.deinit(); - inline for (locales) |locale| { + inline for (internal_os.i18n.locales) |locale| { const msgfmt = b.addSystemCommand(&.{ "msgfmt", "-o", "-" }); msgfmt.addFileArg(b.path("po/" ++ locale ++ ".po")); @@ -106,7 +103,7 @@ fn createUpdateStep(b: *std.Build) !*std.Build.Step { "po/" ++ domain ++ ".pot", ); - inline for (locales) |locale| { + inline for (internal_os.i18n.locales) |locale| { const msgmerge = b.addSystemCommand(&.{ "msgmerge", "-q" }); msgmerge.addFileArg(b.path("po/" ++ locale ++ ".po")); msgmerge.addFileArg(xgettext.captureStdOut()); diff --git a/src/main_c.zig b/src/main_c.zig index 8a66837d3..1b73d7327 100644 --- a/src/main_c.zig +++ b/src/main_c.zig @@ -15,6 +15,7 @@ const build_config = @import("build_config.zig"); const main = @import("main_ghostty.zig"); const state = &@import("global.zig").state; const apprt = @import("apprt.zig"); +const internal_os = @import("os/main.zig"); // Some comptime assertions that our C API depends on. comptime { @@ -88,3 +89,13 @@ export fn ghostty_info() Info { .version_len = build_config.version_string.len, }; } + +/// Translate a string maintained by libghostty into the current +/// application language. This will return the same string (same pointer) +/// if no translation is found, so the pointer must be stable through +/// the function call. +/// +/// This should only be used for singular strings maintained by Ghostty. +export fn ghostty_translate(msgid: [*:0]const u8) [*:0]const u8 { + return internal_os.i18n._(msgid); +} diff --git a/src/os/i18n.zig b/src/os/i18n.zig index c4609bff8..004ae9477 100644 --- a/src/os/i18n.zig +++ b/src/os/i18n.zig @@ -3,6 +3,13 @@ const build_config = @import("../build_config.zig"); const log = std.log.scoped(.i18n); +/// Supported locales for the application. This must be kept up to date +/// with the translations available in the `po/` directory; this is used +/// by our build process as well runtime libghostty APIs. +pub const locales = [_][]const u8{ + "zh_CN.UTF-8", +}; + pub const InitError = error{ InvalidResourcesDir, OutOfMemory,