-
Notifications
You must be signed in to change notification settings - Fork 704
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
gtk: add localization support, take 3 #6004
Conversation
69882c0
to
7c90d20
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm supportive of this but just noting I want to review this. I'm less experienced with this so want to better understand some things that are perhaps trivial or obvious:
- Is it typical for
xgettext
to run during binary build time or should we start considering this as a step we run prior to packaging up our source tarballs for packagers? i.e. is this a dependency on packaging or is this a dependency on source building?
Making it all one step for day to day dev makes total sense, just thinking about the final release time packaging here. I know it's typical for source tarballs to contain some preprocessing complete but unsure if this falls in that category.
- I know it's typical for
po
files to go at the root, but we may want to make a note this is only for GTK currently. I need to do research on what the recommended approach for macOS is (we don't need to solve that in this PR but I want to make sure we're structured right for it)
What I've gathered is that while string catalogs are definitely the recommended translation mechanism from Apple moving forward and are a lot more convenient to use for the macOS apprt ( |
Right, but we're only committing the po files to the repo, right? So if I'm understanding properly, we should plan to run this prior to generating the source tarball so packagers do not need to do this. |
Yeah, my plan is to always update the PO template whenever strings are added, changed or removed in PRs, enforced via CI. That way the template is always accurate to the source files (which is already desirable since they include source locations) and translators always have an up-to-date picture of what strings need to be translated. Packagers don't need to do anything. |
I don't do any i18n/l10n, but I've never been comfortable having the |
That's what I've been planning to do :p |
9749211
to
b78fc1d
Compare
b78fc1d
to
f972e26
Compare
It is better when it is part of the build system, coming from a Meson world. |
Well it is part of the build system (I've added a new top-level step to run it via |
Cool, cool, cool. |
6b1aa3d
to
b782779
Compare
@kenvandine Looks like the snap package needs to be updated with the dependency on gettext. I am completely clueless about snaps, however, so I'd really appreciate some assistance on this front 😅 |
b782779
to
f7b4d92
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good. I want to run this locally later today just to make sure I really understand the full build path here, and that may result in some other code comments but they're likely superficial.
//! 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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think Ghostty even builds for musl right now anyways but this is a good thought regardless to not give us any more debt to work on there. (I think the debt is mainly we have other deps that don't play nice with musl)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah honestly like... I don't even know how people who use musl even manage to coax GTK & Friends to work on it, but if they do manage to do it then I presume they have enough know-how to get localization working
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the snap you need to add gettext to build-packages. Something like the following will work:
diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml
index 49d452ef..9822619d 100644
--- a/snap/snapcraft.yaml
+++ b/snap/snapcraft.yaml
@@ -75,6 +75,7 @@ parts:
- libadwaita-1-dev
- libxml2-utils
- git
+ - gettext
- patchelf
override-build: |
craftctl set version=$(git describe --abbrev=8)
Got it. However, I wonder if if'd work OOTB - I see that LC_ALL is forcibly set to C.UTF-8 and there's some forum threads that suggest more work would be needed for it to work. (e.g. https://forum.snapcraft.io/t/the-gettext-launch-launcher-fix-gettext-based-internationalization-in-the-snap-runtime/9111, https://forum.snapcraft.io/t/lack-of-compiled-locales-breaks-gettext-based-localisation/3758) Is this still accurate? |
f7b4d92
to
9ac2a8a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One very easy change requested. The rest looks good.
I made one commit to update the build files. The only real change there is I think that top-level steps should only be created in build.zig
and our helper structs should create unattached *std.Build.Step
that can be depended on instead.
I also did some minor style modifications to fit an 80 character width, which despite having a large screen I still find helpful for splits.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Snap changes look good, thanks!
18fa342
to
02e6cc1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just some small™ things about the documentation (the Zig looks fine to me).
02e6cc1
to
782bae1
Compare
59482e4
to
3c93e04
Compare
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.
When one develops Ghostty while using Ghostty it could lead to an interesting conundrum: the freshly built Ghostty would use the parent Ghostty's resources, which would be stale and not reflect any new changes to resources. This is especially bad for translators, since their translations would not be reflected in the newly built Ghostty if they happen to run it under older Ghostty, which is not only counterintuitive and also painful in terms of workflow. Now, on debug builds we always try to use the terminfo detection method first in order to locate the zig-out/share/ghostty folder, and only fall back to GHOSTTY_RESOURCES_DIR if the executable is for some reason no longer in zig-out. You can test this behavior by manually moving the Ghostty executable out of zig-out, and then launching it with and without Ghostty.
3c93e04
to
6373399
Compare
…6619) This builds on @pluiedev's excellent #6004. ## Background: The macOS (and libghostty consumer) Plan Broadly, the decision I've come to is that for cross-platform translations (i.e. strings shared across libghostty), we will be using gettext and libghostty will export helper methods to call those (e.g. `ghostty_translate` in this PR for singular forms). To be clear, **this only applies to strings owned by libghostty**. For application-level strings such as macOS-specific menu items and so on, we still have choice but will likely using native features. The reason for this is because converting gettext translations (`po`) to native formats (Xcode String Catalog, `.strings`/`.stringsdict`) is nightmare level, in particular for plural forms. I don't see a robust path to doing it. And if we don't convert and don't use gettext, then translators would have to maintain an identical translation in multiple locations. To make matters worse, the macOS translation formats require Apple-tooling for now unless you want to edit raw JSON. Leveraging gettext lets us share translations across platforms and take advantage of proven tech. ## PR Contents **`pkg/libintl` builds and statically links libintl for macOS.** macOS doesn't ship libintl with the system while Linux generally does with libc, so we need to build this ourselves. This makes gettext available to macOS. libintl is LGPL and we remain in compliance with that despite static linking because our build process is fully open source, so downstream consumers can modify our build scripts to replace it if they wanted to. ~~**`src/os/locale.zig` now sets the `LANGUAGE` environment variable on macOS based on the app's preferred languages.** macOS lets you configure the system locale separate from preferred language. We previously relied solely on `NSLocale.currentLocale`, but this only represents the system locale. We now also look at `NSLocale.preferredLanguages` (a list in priority order) and if we support a given language we set `LANGUAGE` so gettext translates properly. Notably, the above lets us debug translations in Xcode by setting alternate languages for debug builds only.~~ Removed this for a future PR since it was problematic. **`build.zig` unconditionally builds binary `mo` files** since they're required for all apprts now. **The macOS app bundles the translation strings.** This includes our GTK-specific translation strings but the size of these is so small it isn't worth the complexity of splitting up into multiple `pot`s at this time, I think. **i18n APIs moved to `src/os` from `src/apprt/gtk`.** Since these are now cross-platform/cross-apprt, they're a core API. The only notable change here is that `_` now maps to `dgettext` and explicitly specifies our domain so that it's library-friendly. The GTK apprt calls `initGlobalDomain` so that blueprint translations still work. ## Next Steps This PR is all groundwork. The macOS app doesn't leverage any of this yet, although I've verified it all works (e.g. calling the `ghostty_translate` API from Swift). For next steps, we need to have a use case for cross-platform translations and the first one I was looking at was configuration error messages and other core strings.
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