This will relate my short learning journey in implementing a procedural macro in Rust: i18n-format.
The problem
Building Rust applications means having to deal with localization, ie
allowing the UI to be translated in other languages. This is a big
deal for users, and thanks to existing tooling, if you use gtk-rs and
if you use the rust-gtk-template
to boostrap
your project you should be all set. The GNOME community has an history
of caring about this and most of the infrastructure is here.
However there is one sore point into this: gettext, the standard package used to handle strings localization at runtime doesn't support Rust. For some reason the patch to fix it is stuck in review.
While it mostly works, the lack of support cause one thing: the
getttext!
macro that allow the use of localized strings as format
is ignored by the xgettext
command used to extract and strings and
generate the PO template. It is the !
, a part of the macro
invocation syntax in Rust, that is the blocker. Another problem is
that in Rust, for safety reasons, you can only pass a string literal
to format!
, which is why gettext!
exists in the first place.
Until xgettext
is fixed, either these strings are missed in the
localization process, or you end up reimplementing it with less
flexibility. That's what some applications do.
What if I implement a macro that would allow using a function syntax and still use the macro underneath? Oh boy, that mean I need to implement a procedural macro, something I have been dreading because it looks like it has a steep learning curve. It's a topic so complicated that it is glanced over by most books about Rust. Turns out it wasn't that difficult, thanks to a great tooling.
The idea is as follow: convince xgettext
to recognize the string. It
should look like a plain function, while we need to call a macro.