Crate l10n

source ·
Expand description

l10n is a high level and opinionated localization crate built upon the excellent fluent-bundle crate, the Fluent project and inspired by the thiserror crate.

For more informations please visit the code repository: https://github.com/MathieuTricoire/l10n

Simple example

use l10n::unic_langid::langid;
use l10n::{message, message_args, L10nMessage};

l10n::init!({});

fn main() {
    let lang = langid!("fr");

    let username = "Alice";
    let greeting = message!("app", "greeting", "first-name" = username);
    assert_eq!(greeting.translate(&lang), "Bonjour \u{2068}Alice\u{2069} !");

    let status = Status::Busy {
        reason: "Meeting".to_string(),
    };
    assert_eq!(
        status.translate(&lang),
        "\u{2068}Non disponible\u{2069} (\u{2068}Meeting\u{2069})"
    );
    assert_eq!(
        status.translate_with_args(&lang, Some(&message_args!("gender" => "female"))),
        "\u{2068}Occupée\u{2069} (\u{2068}Meeting\u{2069})"
    );
}

#[derive(L10nMessage)]
#[l10n_message("settings", "status")]
enum Status {
    #[l10n_message(".online")]
    Online,
    #[l10n_message(".offline")]
    Offline,
    #[l10n_message(".busy", "reason" = reason.as_str(), "gender" = "other")]
    Busy { reason: String },
}

Advanced example

This example is not really relevant, it is just to show how to use l10n.

use l10n::fluent_bundle::{FluentArgs, FluentValue};
use l10n::unic_langid::langid;
use l10n::L10nMessage;
use std::borrow::Cow;

fn l10n_transform(s: &str) -> Cow<str> {
    Cow::from(s.replace("Occupée", "OcCuPéE🚫"))
}

fn time<'a>(positional: &[FluentValue<'a>], _named: &FluentArgs) -> FluentValue<'a> {
    match positional.get(0) {
        Some(FluentValue::String(s)) => {
            FluentValue::String(Cow::from(format!("{}🕒", s)))
        },
        Some(v) => v.to_owned(),
        _ => FluentValue::Error,
    }
}

l10n::init!({
    use_isolating: false, // Not recommended
    transform: Some(l10n_transform),
    functions: {
        "TIME": time
    }
});

fn main() {
    let lang = langid!("fr");
    let status = Status::BusyFor {
        reason: "Meeting",
        gender: Gender::Female,
        time: Time::minutes(30),
    };
    assert_eq!(status.translate(&lang), "OcCuPéE🚫 (Meeting) [30m🕒]");
}

#[derive(L10nMessage)]
#[l10n_message('a, "settings", "status")]
enum Status<'a, T>
where
    &'a T: 'a + Into<FluentValue<'a>>,
{
    #[l10n_message(".online")]
    Online,
    #[l10n_message(".offline")]
    Offline,
    #[l10n_message(".busy", "reason" = *.0, "gender" = .1)]
    Busy(&'a str, Gender),
    #[l10n_message(".busy-for", *reason, gender, time)]
    BusyFor { reason: &'a str, gender: Gender, time: T },
}

enum Gender {
    Female,
    Male,
    Other,
}

impl<'a> Into<FluentValue<'a>> for &'a Gender {
    fn into(self) -> FluentValue<'a> {
        FluentValue::String(Cow::from(match self {
            Gender::Female => "female",
            Gender::Male => "male",
            Gender::Other => "other",
        }))
    }
}

pub struct Time(usize);

impl Time {
    pub fn minutes(minutes: usize) -> Time {
        Time(minutes)
    }
}

impl<'a> Into<FluentValue<'a>> for &'a Time {
    fn into(self) -> FluentValue<'a> {
        FluentValue::String(Cow::from(format!("{}m", self.0)))
    }
}

Re-exports

pub use once_cell;
pub use l10n_core::fluent_bundle;
pub use l10n_core::intl_memoizer;
pub use l10n_core::unic_langid;

Macros

Structs

Enums

Constants

Traits

Functions

Derive Macros