Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

"Shake Hand!"

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.

How to Use?

1. Add Dependency

Add the following to your Cargo.toml:

shakehand = "0.1"

2. Write Configuration Files

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}!"

3. Load Translations

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 Languages enum listing all languages
  • A set_lang function for switching the current language
  • A unit struct Global (named after global.toml), whose associated functions are the translations for each key

4. Call Translations

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());

5. Fallback Chain (Optional)

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 -> French

The 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.other is the ultimate fallback (falls back to locale!'s fallback parameter if unset).
  • All languages in the chain are automatically added to the Languages enum, even if they have no translations in the locale files.

Contributing

Directly open a PR to the repository and mention @Weicao-CatilGrass.

License

MIT or Apache 2.0

About

A rust i18n lib - Let different languages shake hands with each other!

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages