[][src]Crate i18n_embed

Traits and macros to conveniently embed the output of cargo-i18n into your application binary in order to localize it at runtime.

The core trait for this library is I18nEmbed, which also has a derive macro to allow it to be easily implemented on a struct in your project.

This library makes use of rust-embed to perform the actual embedding of the language files, unfortunately using this currently requires you to manually add it as a dependency to your project and implement its trait on your struct in addition to I18nEmbed. At some point in the future this library may incorperate the embedding process into the I18nEmbed trait and remove this dependency. RustEmbed currently will not compile if the target folder path is invalid, so it is recommended to either run cargo i18n before building your project, or committing the compiled resources to ensure that the project can build without requiring cargo i18n.

Optional Features

The i18n-embed crate has the following optional Cargo features:

Examples

Simple

The following is an example for how to derive the required traits on structs, and localize your binary using this library when it first runs:

use i18n_embed::{I18nEmbed, language_loader, DesktopLanguageRequester};
use rust_embed::RustEmbed;

#[derive(RustEmbed, I18nEmbed)]
#[folder = "i18n/mo"] // path to the compiled localization resources
struct Translations;

language_loader!(MyLanguageLoader);

fn main() {
    let translations = Translations {};
    let language_loader = MyLanguageLoader::new();

    // Use the language requester for the desktop platform (linux, windows, mac).
    // There is also a requester available for the web-sys WASM platform called
    // WebLanguageRequester, or you can implement your own.
    let requested_languages = DesktopLanguageRequester::requested_languages();

    i18n_embed::select(&language_loader, &translations, &requested_languages);

    // continue on with your application
}

Automatic Updating Selection

Depending on the platform, you can also make use of the LanguageRequester's ability to monitor changes to the currently requested language, and automatically update the selected language using a Localizer:

use std::rc::Rc;
use i18n_embed::{
    I18nEmbed, language_loader, DesktopLanguageRequester,
    LanguageRequester, DefaultLocalizer, Localizer};
use rust_embed::RustEmbed;
use lazy_static::lazy_static;

#[derive(RustEmbed, I18nEmbed)]
#[folder = "i18n/mo"] // path to the compiled localization resources
struct Translations;
const TRANSLATIONS: Translations = Translations {};

language_loader!(MyLanguageLoader);

lazy_static! {
    static ref LANGUAGE_LOADER: MyLanguageLoader = MyLanguageLoader::new();
}

fn main() {
    let localizer = DefaultLocalizer::new(
        &*LANGUAGE_LOADER,
        &TRANSLATIONS,
    );

    let localizer_rc: Rc<dyn Localizer> = Rc::new(localizer);

    let mut language_requester = DesktopLanguageRequester::new();
    language_requester.add_listener(Rc::downgrade(&localizer_rc));

    // Manually check the currently requested system language,
    // and update the listeners. When the system language changes,
    // this will automatically be triggered.
    language_requester.poll().unwrap();

    // continue on with your application
}

The above example makes use of the DefaultLocalizer, but you can also implement the Localizer trait yourself for a custom solution. It also makes use of lazy_static to allow the LanguageLoader implementation to be stored statically, because its constructor is not const.

Localizing Libraries

If you wish to create a localizable library using i18n-embed, you can follow this code pattern in the library itself:

use std::rc::Rc;
use i18n_embed::{
   I18nEmbed, language_loader, DesktopLanguageRequester,
   LanguageRequester, DefaultLocalizer, Localizer};
use rust_embed::RustEmbed;
use lazy_static::lazy_static;

#[derive(RustEmbed, I18nEmbed)]
#[folder = "i18n/mo"] // path to the compiled localization resources
struct Translations;
const TRANSLATIONS: Translations = Translations {};

language_loader!(MyLanguageLoader);

lazy_static! {
    static ref LANGUAGE_LOADER: MyLanguageLoader = MyLanguageLoader::new();
}

// Get the `Localizer` to be used for localizing this library.
#[cfg(feature = "localize")]
pub fn localizer() -> Box<dyn Localizer<'static>> {
    Box::from(DefaultLocalizer::new(
        &LANGUAGE_LOADER,
        &TRANSLATIONS
    ))
}

People using this library can call localize() to obtain a Localizer, and add this as a listener to their chosen LanguageRequester.

Localizing Sub-crates

If you want to localize a sub-crate in your project, and want to extract strings from this sub-crate and store/embed them in one location in the parent crate, you can use the following pattern for the library:

use std::rc::Rc;
use i18n_embed::{
   I18nEmbed, language_loader, DesktopLanguageRequester,
   LanguageRequester, DefaultLocalizer, Localizer};
use rust_embed::RustEmbed;
use i18n_embed::I18nEmbedDyn;
use lazy_static::lazy_static;

#[derive(RustEmbed, I18nEmbed)]
#[folder = "i18n/mo"] // path to the compiled localization resources
struct Translations;

const TRANSLATIONS: Translations = Translations {};

language_loader!(MyLanguageLoader);

lazy_static! {
    static ref LANGUAGE_LOADER: MyLanguageLoader = MyLanguageLoader::new();
}

// Get the `Localizer` to be used for localizing this library,
// using the provided embeddes source of language files `embed`.
pub fn localizer(embed: &'static dyn I18nEmbedDyn) -> Box<dyn Localizer<'static>> {
    Box::from(DefaultLocalizer::new(
        &*LANGUAGE_LOADER,
        embed
    ))
}

For the above example, you can enable the following options in the sub-crate's i18n.toml to ensure that the localization resources are extracted and merged with the parent crate's pot file:

# ...

[gettext]

# ...

# (Optional) If this crate is being localized as a subcrate, store the final
# localization artifacts (the module pot and mo files) with the parent crate's
# output. Currently crates which contain subcrates with duplicate names are not
# supported.
extract_to_parent = true

# (Optional) If a subcrate has extract_to_parent set to true, then merge the
# output pot file of that subcrate into this crate's pot file.
collate_extracted_subcrates = true

Re-exports

pub use gettext;
pub use tr;
pub use unic_langid;

Macros

language_loader

A procedural macro to create a struct and implement the LanguageLoader trait on it.

Structs

DefaultLocalizer

A simple default implemenation of the Localizer trait.

DesktopLanguageRequester

A LanguageRequester for the desktop platform, supporting windows, linux and mac. It uses locale_config to select the language based on the system selected language.

WebLanguageRequester

A LanguageRequester for the web-sys web platform.

Enums

I18nEmbedError

An error that occurs in this library.

Traits

I18nEmbedDyn

A dynamic reference to a static I18nEmbed implementation.

I18nEmbed

A trait to handle the embedding of software translations within the current binary, and the retrieval/loading of those translations at runtime.

LanguageLoader

A trait used by I18nEmbed to load a language file for a specific rust module using a specific localization system. The trait is designed such that the loader could be swapped during runtime, or contain state if required.

LanguageRequester

A trait used by I18nEmbed to ascertain which languages are being requested.

Localizer

This trait provides dynamic access to an LanguageLoader and an I18nEmbed, which are used together to localize a library/crate on demand.

Functions

domain_from_module

Get the translation domain from the module path (first module in the module path).

select

Select the most suitable language currently requested by the system by the the LanguageRequester, and load it using the provided LanguageLoader from the languages embedded in I18nEmbed via I18nEmbedDyn. Returns the language that was negotiated to be selected.

select_single

Load a language with language_id using the provided LanguageLoader from the languages embedded in I18nEmbed via I18nEmbedDyn.

Derive Macros

I18nEmbed

A procedural macro to implement the I18nEmbed trait on a struct.