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! ```
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" ```
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.
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.
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
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).
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!
} ```
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.