Skip to content

tronicboy1/axum_l10n

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

31 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

About this Crate

This crate offers some localization tools to be used with Axum.

Basic usage

You can use this crate to extract a language identifier (ex en-US) from a request.

If the mode is set to RedirectMode::NoRedirect, the Accept-Language header is used to find the users preferred language. If the mode is set to either RedirectMode::RedirectToFullLocaleSubPath or RedirectMode::RedirectToLanguageSubPath, the user will be redirected to a sub-path based on their Accept-Language headers, to to the default language if not supported.

use unic_langid::{langid, LanguageIdentifier};
use axum::Extension;

pub const ENGLISH: LanguageIdentifier = langid!("en");
pub const JAPANESE: LanguageIdentifier = langid!("ja");

let router = axum::Router::new()
      .route("/lists", get(|Extension(lang): Extension<LanguageIdentifier>|
        async move {
          Html(format!("Your language is: {}", lang.to_string()))
        }))
      .layer(axum_l10n::LanguageIdentifierExtractorLayer::new(
          ENGLISH,
          vec![ENGLISH, JAPANESE],
          axum_l10n::RedirectMode::NoRedirect,
      ));

For RedirectMode::RedirectToFullLocaleSubPath or RedirectMode::RedirectToLanguageSubPath, you must wrap this service/middleware around the entire axum app, as explained here.

When using the subpath redirect modes, you may want to exclude some folders from the redirect as below:

let l10n_middleware = axum_l10n::LanguageIdentifierExtractorLayer::new(
        JAPANESE,
        vec![JAPANESE, ENGLISH],
        axum_l10n::RedirectMode::RedirectToLanguageSubPath,
    )
    .excluded_paths(&["/api", "/assets", "/auth"]);

Features

fluent

Enabling fluent allows you to use the fluent Localizer to add bundles for translation.

See fluent-rs for details about fluent and rust.

Usage

use unic_langid::{langid, LanguageIdentifier};
use axum_l10n::Localizer;

pub const ENGLISH: LanguageIdentifier = langid!("en");
pub const JAPANESE: LanguageIdentifier = langid!("ja");
let mut localizer = Localizer::new();

localizer
    .add_bundle(JAPANESE, &["locales/ja/main.ftl", "locales/ja/login.ftl"])
    .unwrap();
localizer
    .add_bundle(ENGLISH, &["locales/en/main.ftl", "locales/en/login.ftl"])
    .unwrap();

let message = localizer.format_message(&ENGLISH, "test-key-a", None);

assert_eq!(Some(String::from("Hello World")), message);

tera

Enabling the tera feature allows you to use the fluent translations inside tera templates.

See tera for more information on tera.

Usage

Initialization:

use tera::Tera;

let mut tera = Tera::new("src/views/templates/**/*").expect("tera parsing error");

let mut localizer = Localizer::new();

localizer
    .add_bundle(ENGLISH, &["locales/en/main.ftl", "locales/en/login.ftl"])
    .unwrap();

tera.register_function("fluent", localizer);

Axum handler:

#[derive(Clone)]
struct ViewRouterState {
    pool: mysql_async::Pool,
    tera: Arc<tera::Tera>,
}

async fn lists_view(
    State(state): State<ViewRouterState>,
    Extension(lang): Extension<LanguageIdentifier>,
) -> axum::response::Response {
    let lists: Vec<String> = List::paginate(&state.pool, claim.sub)
        .await.unwrap();

    let mut ctx = Context::new();
    ctx.insert("lists", &lists);
    ctx.insert("lang", &lang);

    let html = state.tera.render("lists.html", &ctx).unwrap();

    Html(html).into_response()
}

In tera template:

<label for="family-id">{{ fluent(key="list-family", lang=lang) }}</label>
<select name="family-id" id="family-id">
  {% for family in families %}
  <option value="{{ family.family_id }}">{{ family.family_name }}</option>
  {% endfor %}
</select>

About

A crate with localization utilities for Axum

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published