Let different languages shake hands with each other! 🤝
This is a purely compile-time Rust internationalization library. All localized strings are fully embedded into the binary at compile time, with only minimal runtime overhead.
Add the following to your Cargo.toml:
shakehand = "0.1"Create a directory under your project to serve as the root for translations, e.g. ./locale/.
Create any toml file inside this directory, e.g. ./locale/global.toml, representing a translation file.
In the file, group translations by language section. The key is the translation key, and the value is the translated text.
Text with parameters uses %{parameter_name} as placeholders, where the parameter name directly maps to the generated function's parameter name:
[en]
world = "world"
greeting = "Hello, %{someone}!"
[zh_CN]
world = "世界"
greeting = "你好,%{someone}!"In your Rust code, use shakehand::locale! to hardcode the entire directory into a module:
pub mod translation {
shakehand::locale!("./locale", fallback = "en");
}The generated module will contain:
- A
Languagesenum listing all languages - A
set_langfunction for switching the current language - A unit struct
Global(named afterglobal.toml), whose associated functions are the translations for each key
Call translations just like ordinary functions, passing parameters by placeholder name:
use crate::translation::{Global, Languages, set_lang};
fn main() {
set_lang(Languages::en);
let greeting = Global::greeting("World");
println!("{}", greeting); // Hello, World!
set_lang(Languages::zh_CN);
let greeting = Global::greeting("世界");
println!("{}", greeting); // 你好,世界!
}You can also pass the return value of another translation as a parameter, since each parameterless translation function returns a &'static str, completely allocation-free:
let greeting = Global::greeting(Global::world());You can configure a fallback chain in your Cargo.toml under [package.metadata.shakehand].
When a language has no translation for a key, the system will automatically walk the chain to find the nearest language that has one.
[package.metadata.shakehand]
# For any language not explicitly listed, fall back to English
fallback.other = "en"
# Specific fallback rules
fallback.zh_HK = "zh_CN" # Hong Kong Trad -> Simplified Chinese
fallback.zh_TW = "zh_CN" # Taiwan Trad -> Simplified Chinese
fallback.zh_CN = "en" # Simplified Chinese -> English
fallback.it = "fr" # Italian -> FrenchThe chain resolution is at runtime via a generated FallbackSolver:
- Each language has a
try_fallback_once()step defined in a compile-time generated match. - Translation functions loop through the chain until a language with the value is found.
fallback.otheris the ultimate fallback (falls back tolocale!'sfallbackparameter if unset).- All languages in the chain are automatically added to the
Languagesenum, even if they have no translations in the locale files.
Directly open a PR to the repository and mention @Weicao-CatilGrass.
MIT or Apache 2.0