kellpossible / cargo-i18n

A Rust Cargo sub-command and libraries to extract and build localization resources to embed in your application/library
MIT License
120 stars 24 forks source link

Simple fmt based localization using serde/miniserde #87

Open kellpossible opened 2 years ago

kellpossible commented 2 years ago

Provide a localization method that accepts strings coming from a dictionary via a serde, nanoserde, miniserde, microserde format such as json, yaml, toml, ron, etc. Or perhaps also some binary formats like messagepack or bincode.

Strings can contain formatting syntax which can be either specified by the user, or use something like ufmt, runtime_fmt, dynfmt or something like minijinja/handlebars.

The primary use cases would be:

kellpossible commented 2 years ago

And perhaps having the full flexibility/generalization of these formats with serde/miniserde, etc isn't necessary for a simple message dictionary, given their additional cost if we were to make them necessary for all of the formats. Something like postcard or lite-json could also be good.

kellpossible commented 2 years ago

Having support for converting between the formats at compile time would also be good, so the data can be stored in the repository an any format, and converted to a format that meets the needs of the application at runtime. For embedded this could mean having a wider range of repo storage formats, and on device a nice slim binary format.

kellpossible commented 2 years ago

I think the interface should be mostly covered by traits, and left to the examples for how to implement them. Maybe have a default implementation for serde and ufmt.

For each of the data formats, something like this:

trait FmtLocalizationDictionary<'m> {
    fn get(message_id: &str) -> &'m str;
}

/// Not needed for no_std, useful for conversions during build and for editing translations.
trait FmtLocalizationDictionaryMut<'m>: FmtLocalizationDictionary<'m> {
    fn set(message_id: &str, new_message: String) -> String;
}

For each of the formatting methods, maybe something like this?

trait MessageFormatter {
    fn format_message(message: &str) -> String;
}

Could also get some inspiration from the generic formatter design in ufmt.

Ideally the client will be requesting the formatter via some API where they can pass in a fixed size buffer from the stack to receive the results of the localized message.

Perhaps this generic message formatting support and decoupling from storage formats will link in well with #42