rosetta-i18n

Crates.io docs.rs CI

rosetta-i18n is an easy-to-use and opinionated Rust internationalization (i18n) library powered by code generation.

```rust rosettai18n::includetranslations!();

println!(Lang::En.hello("world")); // Hello, world! ```

Features

Installation

Rosetta is separated into two crates, rosetta-i18n and rosetta-build. To install both, add the following to your Cargo.toml:

```toml [dependencies] rosetta-i18n = "0.1"

[build-dependencies] rosetta-build = "0.1" ```

Getting started

The following guide explains how to use rosetta-i18 to manage your translations. Please refer to the crate documentation for in depth explanations about the exposed types.

1- Writing translation files

First, we have to write translation files in JSON format, for example in a /locales directory. The format is similar to other translations libraries.

locales/en.json json { "hello": "Hello world!", "hello_name": "Hello {name}!" }

In this example, we defined two keys, hello and hello_name. The first is a static string, whereas the second contains the name variable which will be replaced at runtime by the value of your choice. Note that nested key are not (yet?) supported.

Then, create a file for each language you want. It is not required that all files contain all keys. We will define a fallback language later.

2- Generate code from translation files

Code generation use a build script, which will be run each time you edit a translation file. Let's create a build.rs file at the root folder of your crate (same folder as the Cargo.toml file).

build.rs ```rust fn main() -> Result<(), Box> { rosetta_build::config() .source("en", "locales/en.json") .source("fr", "locales/fr.json") .fallback("en") .generate()?;

Ok(())

} ```

This script will use the rosetta_build crate. In this example, we define two languages: en and fr. Languages identifiers must be in the ISO 639-1 format (two-letters code). The en language is defined as fallback, so if a key is not defined in our fr.json file, the English string will be used. The output type name can also be customized with the .name() method, as well as the output folder with the .output() method.

Then, call the .generate() method to generate the code. By default, it will be generated in a folder inside the target directory (OUT_DIR env variable).

3- Use generated type

The generated type (named Lang except if you defined another name - see the previous section) must be included in your code with the include_translations macro. A good practice is to isolate it in a dedicated module.

Each translation key is transformed into a method, and each language into an enum variant.

src/main.rs ```rust mod translations { rosettai18n::includetranslations!(); }

fn main() { use translations::Lang;

println!("{}", Lang::En.hello());  // Hello world!
println!("{}", Lang::En.hello_name("Rust"));  // Hello Rust!

} ```

Contributing

There is no particular contribution guidelines, feel free to open a new PR to improve the code. If you want to introduce a new feature, please create an issue before.