cargo-i18n icon indicating copy to clipboard operation
cargo-i18n copied to clipboard

Simple fmt based localization using serde/miniserde

Open kellpossible opened this issue 3 years ago • 3 comments

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:

  • Support backwards compatibility with existing data or legacy pipelines.
  • Make it possible to have an extremely small/simple localization system for embedded/no_std use cases. This will also involve seeing how to make i18n-embed support no_std.

kellpossible avatar Feb 20 '22 06:02 kellpossible

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 avatar Feb 20 '22 06:02 kellpossible

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 avatar Feb 20 '22 06:02 kellpossible

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

kellpossible avatar Feb 20 '22 06:02 kellpossible