Dynamic string formatting

Rust's built-ins already support compile-time formatting. But what if you have, say, a JSON containing language resources such as follows?

res/lang/en-us/_.json

{
    "welcome": "Welcome, $p!"
}

I needed something simple to replace this $p sequence, not a full-fledged template framework. I provided a handy utility which can optionally process its own arguments to the string parameters.

It looks a bit cryptic because arguments are Box<dyn Any>.

use rialight_util::template_string;

fn main() {
    // formatting (processor, the 3rd argument, is optional)

    let applied = template_string::apply("$<foo-qux>", &template_string::map! { "foo-qux" => "Fq" }, None);
    assert_eq!(applied, "Fq".to_owned());

    let applied = template_string::apply("$<foo-qux>", &template_string::map! { "foo-qux" => "Fq" }, Some(|v| (*v.downcast_ref::<&'static str>().unwrap()).to_owned()));
    assert_eq!(applied, "Fq".to_owned());

    let applied = template_string::apply("$<foo-qux>", &template_string::map! {}, None);
    assert_eq!(applied, "None".to_owned());

    // constructing a template_string::Map

    let map = template_string::map!{
        "a" => "foo",
        "b" => "bar",
    };
    assert_eq!(*map[&"a".to_owned()].downcast_ref::<&'static str>().unwrap(), "foo");
    assert_eq!(*map[&"b".to_owned()].downcast_ref::<&'static str>().unwrap(), "bar");
    assert!(map.get(&"c".to_owned()).is_none());
}

More information:

  • rialight_util::template_string::Map is equivalent to HashMap<String, Box<dyn Any>>.
  • formatting syntax: $<person-name>
  • formatting syntax: $personname (parameter without hyphens or underscores)
  • formatting syntax: $$ (single dollar)

Here's the implementation: template_string.rs

It's available on crates.io:

[dependencies]
rialight_util = "1"

For translations you might want to take a look at Fluent. ("A localization system
for natural-sounding translations.") This is what Firefox uses and what rustc is in the process of migrating to for error messages.

4 Likes

I've done a crate similiar to Fluent too previously. I never tried Fluent, but I found my one more handy at one aspect - it loads bundles for you without much hassle. However I suppose Fluent supports more things, like more complex parameters in their resources?

I'm still in the process of rewritting my internationalization crate, but anyway my previous Fluent alternative is still in crates.io: rialight_localization

Yeah, as I understand it Fluent aims to allow translations even for languages significantly different from English. For example it allows you to handle plurality beyond just one, two, many, it allows using the correct for of words depending on the gender of the subject in languages that need this. This does indeed come at the cost of higher complexity, which your crate probably wins on. I think the fluent-fallback crate allows for convenient loading of multiple translation bundles, but I have used neither fluent-fallback nor your crate, so I can't judge which one is better on this regard.

3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.