Koka / gettext-rs

GNU Gettext FFI binding for Rust
51 stars 25 forks source link

No way to test translated strings #90

Open mks-h opened 2 years ago

mks-h commented 2 years ago

There is currently no way to force gettext functions to return specific strings. This means I cannot test if the macros I'm working on at #89 fall back to default strings when returned ones are broken. I believe there are two ways to solve the problem:

  1. For testing, use container populated with translation files;
  2. Fake gettext functions and use some magic of constants to specify which string to return.

I find the first option too cumbersome, so I'll investigate second.

Minoru commented 2 years ago

I'm on the road right now, so just a couple pointers. I can clarify on Sunday if you have questions.

bindtextdomain() takes a path to a directory with a structure similar to /usr/locale. We can create such a directory and populate it with known data, which we will then request via gettext() and friends.

The data is described by a PO file, and compiled into MO files which are put into the locator directory under an appropriate language tag. See gettext manual and /usr/locale on your own machine.

mks-h commented 2 years ago

We can create such a directory and populate it with known data, which we will then request via gettext() and friends.

Yeah, but we will have to initialize it before testing somehow, which is cumbersome.

I have came up with a solutrion that will suffice for now. The idea is to, in each testing function, have an inlined module with a "gettextrs" name that declares a fake gettext function and reexports formatter from the actual gettextrs. Like so:

#[test]
fn nothing_to_format_translated() {
    mod gettextrs {
        pub use ::gettextrs::formatter;
        pub fn gettext<T: Into<String>>(_msgid: T) -> String {
                "Привіт, світ!".into()
        }
    }

    assert_eq!(gettext!("Hello, World!"), "Привіт, світ!");
}

I've put up a declarative macro that simplifies the generation of a module. So, in the end, it looks like so:

#[test]
fn nothing_to_format_translated() {
    fake!(gettext, "Привіт, світ!");

    assert_eq!(gettext!("Hello, World!"), "Привіт, світ!");
}

This approach limits me to using one message per test, which is fair. The problem is that it works because procedural gettext macros use gettextrs::gettext(...) path's which can be confused with a gettextrs module. I could have used ::gettextrs::gettext(...), which can't be confused, but then there is also a feature in cargo that allow renaming dependencies for which I have to get the actual name of the crate anyway... So I'll deal with that later.

I'll leave this issue open for now since it will have to be revisited.

mks-h commented 2 years ago

The other problem is that I have to duplicate function definitions, which might get out of sync with actual implementations. Not an issue today, but it can certainly become one.