gtk-rs / gtk-rs-core

Rust bindings for GNOME libraries
https://gtk-rs.org/gtk-rs-core
MIT License
272 stars 103 forks source link

Provide i18n support #776

Open bilelmoussaoui opened 1 year ago

bilelmoussaoui commented 1 year ago

Currently, gtk-rs based application that has to handle translations makes use of gettext-rs crate. It has some disadvantages like it shipping a gettext tarball when building under windows/macos(i think) which makes the vendored tarball of such applications pretty large for nothing when they target linux only.

Those gtk-rs applications also make use of various functions that are copy pasted between those applications, see https://gitlab.gnome.org/World/amberol/-/blob/main/src/i18n.rs for example. As glib itself provides helpers for making an application translatable, it would be nice to provide/expose some helper/wrapper functions.

cc @jf2048

jf2048 commented 1 year ago

We should provide some better wrappers for the functions glib provides in glib/ggettext.h, and also maybe a rust version of gi18n.h and gi18n-lib.h.

For issues with gettext-rs I think it would be better to try to upstream another feature flag that does what we want. Everything else about that crate is fine, and it is still needed for some of the other gettext functions and enums anyway.

sdroege commented 1 year ago

For issues with gettext-rs I think it would be better to try to upstream another feature flag that does what we want.

What are those issues? Build-time / shipping issues like including a gettext tarball and building the C library are nothing you can cleanly handle via cargo features unfortunately.

jf2048 commented 1 year ago

But it already does handle linking to the system library with a feature flag: https://github.com/Koka/gettext-rs/blob/ea91043635cfc44f442379d2b552166b7ec981a5/gettext-sys/build.rs#L88

We just need another flag that skips the compiling and uses a stub.

jf2048 commented 1 year ago

BTW, this issue might be related to gettext-rs shipping its own copy: https://github.com/gtk-rs/gtk3-rs/issues/755

sdroege commented 1 year ago

cargo feature flags are supposed to be additive, so they don't really work for build configuration. It's something that has to be configured by whoever builds the final application, not by some crate somewhere in the dependency tree. Unfortunately cargo doesn't really have any mechanism for such configurations.

bilelmoussaoui commented 1 year ago

The problem is the version uploaded to crates.io contains the tarball already, so it is not something you can avoid when cargo vendoring.

jf2048 commented 1 year ago

Hmm, then that library should probably be forked. Unless we are ok with copying all functions into the glib crate

sdroege commented 1 year ago

Why not, it's not a lot of code. Or a separate glib-i18n crate in here that does all this, which might be slightly cleaner because it's not exactly "GLib bindings" anymore :)

We'd need that anyway so it makes use of our NULL-terminated string types or not?

sdroege commented 1 year ago

Also in relation to the Rust proxy-libintl implementation we talked about yesterday

jf2048 commented 1 year ago

WIP branch with a glib-i18n package here: https://github.com/jf2048/gtk-rs-core/commit/63131f742303ae1b43a18fa8731ac20a27442598

It supports string formatting and has most of the functions from gettext.h, and a rust reimplementation of proxy-libintl

jf2048 commented 1 year ago

I guess after playing around with this a bit, I am skeptical compared to a native Rust implementation like gettext which is actually less code than my glib-i18n library. If we use the C functions we always have to scan the strings for the null terminator. But the string lengths are actually in the .mo files, a fast Rust implementation could memory map the file and just return pointers into it. (See https://github.com/justinas/gettext/issues/11)

sdroege commented 1 year ago

If that works smoothly and consistent with other (C) applications then sure, why not.

sdroege commented 1 year ago

Let's move this to next milestone then. @jf2048 what's your plans/ideas/status here?

jf2048 commented 1 year ago

Benchmark a pure rust implementation versus the glibc gettext and see what we need to do to improve it. It is possible we can end up more performant than C code by doing compile-time string hashing. I am not sure if it makes sense to try to reimplement the hashing algorithm from gettext or go with another one like const-fnv1a-hash. We cannot avoid .mo files because GtkBuilder uses it, but if needed we can extend it with another file that contains some of our own hashing.