i18n-format

Crates.ioi18n-format
lib.rsi18n-format
version0.4.0
created_at2023-01-21 17:18:34.508919+00
updated_at2025-12-25 16:27:40.442601+00
descriptionA simple macro to allow formatting with gettext with a workaround for older xgettext
homepage
repositoryhttps://github.com/hfiguiere/i18n-format
max_upload_size
id764466
size18,151
Hubert Figuière (hfiguiere)

documentation

https://docs.rs/i18n-format/

README

i18n-format

Note: This crate has been updated from 0.3.0 in how it works, read carefully

See also the update section further down to port

This crate is a helper for using gettext. format! doesn't support non static formatting strings. The gettextrs crate doesn't offer a formatting version as the formatting macro gettext! was removed. Using alternatives with gettext lead to relatively verbose code.

To use the crate just add the following to your Cargo.toml

i18n-format = "0.4.0"

With this crate, getting a formatted localised string is as simple as this:

use i18n_format::{i18n_format, i18n_nformat};

let filename = "file name";
let message = i18n_format!("Loading \"{}\"...", filename);

let count = 2;
let message = i18n_nformat!("Found {} file.",
                            "Found {} files.", count, count);

Then with the proper keyword, xgettext (starting with 0.24) will properly extract the strings. See meson support for details on setting the keywords.

The goal over time is to make this crate obsolete, but in the mean time it is here to help.

If you can't guarantee xgettext 0.25 as part of the developer setup, you can use the legacy mode.

Legacy mode

The legacy mode is enabled with the legacy crate feature.

i18n-format = { version = "0.4.0", features = "legacy" }

xgettext is used to extract strings from source files. Unfortunately it doesn't support Rust. The patch got merged in Jan 2025. This has been released for 0.24.

Fortunately it almost work. You can specify the keyword gettext or whatever alias you use (I usually use i18n). But it can't take a "keyword" that ends in ! like a Rust macro which make using localised string format harder to use.

The legacy mode use a proc macro to enclose a section of localised string use with a placholder function call that is compatible with xgettext extraction for .po files, and a compile time replacement to produce a macro for formatting. Specify i18n_fmt and i18n_nfmt (the two placholders) as keywords for calls to xgettext, and then write your formatting gettext call like this:

use i18n_format::i18n_fmt;

let number = 1;
let s = i18n_fmt! {
    i18n_fmt("This is number {}, make it so !", number)
};

is equivalent to

use formatx::formatx;
use gettextrs::gettext;

let number = 1;
let s = formatx!(gettext("This is number {}, make it so !"), number);

We use the formatx! macro from the crate of the same name. The latter example wouldn't even compile if we used format!, as it expects a literal. And the strings will be extracted with xgettext.

The i18n_fmt function is just a placeholder in the inner block of q i18n_fmt!, and it will be replaced by another macro that will call gettext. To call ngettext for plural forms, just use i18n_nfmt as a placeholder inside the macro.

Error

The underlying [formatx::formatx!] macro will panic in some cases. When it returns an error, i18n_format! will output the error instead of the string.

Meson support

The original use case of this crate was for gtk-rs apps built with meson. If you use the regular gtk-rust-template, internationalisation support is mostly setup. The po/meson.build file should contain a section like this:

i18n.gettext(gettext_package, preset: 'glib')

Just add to the args the following to the i18n.gettext function:

  args [
    '--keyword=i18n_format!',
    '--keyword=i18n_nformat!:1,2'
  ]

This only work of you have xgettext 0.24 or older.

If you use the legacy form, for older gettext, do this:

  args [
    '--keyword=i18n_fmt',
    '--keyword=i18n_nfmt:1,2'
  ]

If args already exist, just add the items to the list.

Both can be commbined without side effect if your codebase hasn't been migrated.

Upgrading from 0.3.0

Upgrading from 0.3.0, just build with the legacy feature and the old syntax will work. If you have gettext 0.24 or later, you can starting using the new form along with the legacy one. Don't forget to update the keywords xgettext if you also use the new form. If you migrate to the new simpler syntax, just keep the default features for the crate and update the keywords for xgettext.

Future

Now that native Rust support exist in gettext 0.24, the only thing remaining is the formatting macros (unless you use the legacy feature).

When gettextrs get support for this happens, these crates will be obsolete.

License

This crate is licensed under the MIT license.

Author: Hubert Figuière hub@figuiere.net

Commit count: 19

cargo fmt