Configuration

Internationalisation (i18n)

Runique includes a lightweight i18n system with no external dependencies.

Supported languages

Lang variantCodeRecognised locale examples
Lang::Frfrfr, fr-FR, fr-CA, fr-BE, fr-CH
Lang::Enenen, en-US, en-GB, en-CA
Lang::Dedede, de-DE, de-AT, de-CH
Lang::Eseses, es-ES, es-MX, es-AR
Lang::Ititit, it-IT, it-CH
Lang::Ptptpt, pt-PT, pt-BR
Lang::Jajaja, ja-JP
Lang::Zhzhzh, zh-CN, zh-TW, zh-HK
Lang::Rururu, ru-RU, ru-BY, ru-UA

The default language is Lang::En when no explicit configuration is provided.


Available API

use runique::utils::trad::{set_lang, current_lang, t, tf, Lang};

// Set the global language
set_lang(Lang::Fr);

// Read the active language
let lang = current_lang(); // → Lang::Fr

// Translate a key
let msg = t("forms.required"); // → "This field is required"

// Translate a key with parameters (replaces {} with arguments)
let msg = tf("forms.too_short", &[3]); // → "Too short (min 3)"
FunctionSignatureDescription
set_langfn set_lang(lang: Lang)Sets the global application language
current_langfn current_lang() -> LangReturns the active language (default: En)
tfn t(key: &str) -> Cow<'static, str>Translates a simple key
tffn tf<T: Display>(key: &str, args: &[T]) -> StringTranslates a key with {} substitutions

Key format

Keys follow dot notation "section.sub_section.key" matching the hierarchy of the translation JSON.

"forms.required"       → { "forms": { "required": "..." } }
"forms.too_short"      → { "forms": { "too_short": "Too short (min {})" } }
"error.not_found"      → { "error": { "not_found": "..." } }

Each {} in a value is replaced sequentially by the arguments passed to tf.


Fallback behaviour

If a key is missing in the target language, Runique applies the following fallback:

  1. Look up the key in the configured language (e.g. Lang::Fr)
  2. If absent, try Lang::En
  3. If still absent, return the raw key (e.g. "forms.required")

This mechanism guarantees that an incomplete translation never causes a panic.


Configuration in `main.rs`

Call set_lang() before building the app, typically right after loading the configuration:

use runique::prelude::*;
use runique::utils::trad::{set_lang, Lang};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = RuniqueConfig::from_env();

    // Set the application language
    set_lang(Lang::Fr);

    RuniqueApp::builder(config)
        .routes(urls::routes())
        .with_database(db)
        .build()
        .await?
        .run()
        .await?;

    Ok(())
}

The language set here applies to user-facing messages: form validation and error messages. Internal logs (tracing::warn!) are hardcoded in French in the source and are not translated.


`LANG` variable for the CLI

The runique CLI reads the LANG environment variable (or LC_ALL / LC_MESSAGES as fallback) to choose its own display language.

Important: LANG in .env only applies to the CLI (runique start, runique new, etc.). The web application language is controlled by set_lang() in main.rs.

Priority for the CLI:

  1. LANG variable in .env (loaded via dotenvy)
  2. System LANG / LC_ALL / LC_MESSAGES variable
  3. En by default if no variable is defined or recognised
# .env — CLI only
LANG=fr

Full locale strings are normalised automatically: fr_FR.UTF-8 is interpreted as fr.