3 unstable releases

new 0.5.1 Mar 10, 2025
0.5.0 Mar 10, 2025
0.4.0 Mar 9, 2025

#388 in Internationalization (i18n)

Download history 68/week @ 2025-03-04

68 downloads per month
Used in 2 crates (via local-fmt-macros)

MIT license

44KB
999 lines

LocalFmt: Provide simple localizable format strings

LocalFmt on crates.io LocalFmt on docs.rs

Overview

local-fmt is a Rust library designed to simplify the process of creating applications that support multiple languages. It allows developers to define localizable format strings in a structured and maintainable way, using familiar file formats like TOML, JSON, and YAML.

Crate Configuration Features

To customize the functionality of local-fmt, you can enable the following features in your Cargo.toml:

  • serde: Enables serialization and deserialization of messages, allowing you to save and load message configurations from various formats. This feature is useful for persistent storage or network transmission of localized messages.
  • macros: Includes macros such as gen_static_message, gen_alloc_message, and def_local_fmt. If you use def_local_fmt, choose one of the following:
    • macros-toml: Enables parsing of TOML files.
    • macros-json: Enables parsing of JSON files.
    • macros-yaml: Enables parsing of YAML files.

Install

[dependencies]
enum-table = "0.2" # Required if you use `def_local_fmt` macro or
                   # call the `new` function of LocalFmt
local_fmt = { version = "0.5", features = ["macros", "macros-toml"] }

Key Features

  • Localizable Messages: Easily define messages in multiple languages using TOML, JSON, or YAML files.
  • Dynamic Language Switching: Change the language at runtime using a function pointer, allowing for flexible language management.
  • Compile-time Checks: Ensure the correctness of message formats at compile time by:
    • Verifying that the number of arguments matches the placeholders.
    • Ensuring that all required arguments are present.
    • Providing detailed error messages that specify which language key is affected, helping you quickly identify and resolve issues.
  • Integration with Serde: Optionally serialize and deserialize messages for persistent storage or network transmission.

Usage Example

Here's a simple example demonstrating how to use local-fmt in a Rust project. This example shows how to create a localizable format string and use it to format a message.

#![cfg(feature = "macros")]
#![cfg(feature = "macros-toml")]

use std::sync::RwLock;
use enum_table::Enumable;
use local_fmt::{def_local_fmt, StaticMessage};

#[derive(Clone, Copy, Enumable)]
enum Lang {
    EN,
    JA,
}

struct Words {
    // If there are no placeholders, use &'static str instead of StaticMessage<0>
    pub ownership: &'static str,
}

// Nested struct example
struct Messages {
    // StaticMessage<Generic>, Generic is usize, representing the number of unique placeholders in the format string.
    // For example, in the format string "Hello, {0} and {1}", the Generic would be 2 because there are two unique placeholders.
    // Duplicate placeholders like "Hello, {0} and {0}" would still result in a Generic of 1, as only one unique placeholder is used.
    // This ensures that the number of arguments provided during formatting matches the number of unique placeholders.
    pub hello: StaticMessage<1>,
    pub words: Words,
}

static LANG: RwLock<Lang> = RwLock::new(Lang::EN);

def_local_fmt!(
    name = MESSAGES,
    lang = Lang,
    message = Messages {
      words: Words,
    },
    supplier = || *LANG.read().unwrap(),
    file_type = "toml",
    lang_folder = "doctest/langs"
);

// Example content of doctest/lang/EN.toml

// hello = "Hello, world! {0}"
//
// [words]
// ownership = "ownership"

fn main() {
    // Use the `MESSAGES` to create a personalized greeting message.

    // StaticMessage provides a `pub fn format(args: &[&str; Generic])` method, where you pass a slice of arguments.
    // The length of the slice must match the number of unique placeholders specified by the Generic parameter.
    // This ensures that each placeholder in the format string is replaced by a corresponding argument.
    assert_eq!(MESSAGES.hello.format(&["Rust"]), "Hello, world! Rust");
    assert_eq!(MESSAGES.words.ownership, "ownership");

    // Change the language to Japanese
    *LANG.write().unwrap() = Lang::JA;

    // Print the greeting message in Japanese
    assert_eq!(MESSAGES.hello.format(&["Rust"]), "こんにちは、世界! Rust");
    assert_eq!(MESSAGES.words.ownership, "所有権");
}

For more detailed information on def_local_fmt, see the documentation.

License

Licensed under

Dependencies

~0.2–1MB
~24K SLoC