yewi18n

Crates.ioyewi18n
lib.rsyewi18n
version0.1.0
created_at2025-11-25 22:10:58.77996+00
updated_at2025-11-25 22:10:58.77996+00
descriptionA simple i18n library for Yew applications with dynamic JSON loading
homepage
repositoryhttps://gitlab.illuminodes.com/illuminodes/yew-i18n
max_upload_size
id1950520
size52,837
Diego Pardo (Pardx-7)

documentation

README

yew-i18n

A simple internationalization (i18n) library for Yew applications that dynamically loads translation JSON files from the browser, similar to how CSS and images are loaded.

Features

  • Dynamic JSON loading via fetch API (no compile-time embedding)
  • Automatic browser language detection
  • Yew context provider for easy integration
  • Simple hook-based API
  • Clippy-compliant code with strict linting rules

Installation

Add this to your Cargo.toml:

[dependencies]
yew-i18n = { path = "../yew-i18n" }
# or once published:
# yew-i18n = "0.1"

Usage

1. Setup Translation Files

Create JSON translation files in your static directory:

static/
└── language/
    ├── en-US.json
    └── es-ES.json

Example en-US.json:

{
  "welcome_message": "Welcome to our app!",
  "login_button": "Login",
  "signup_button": "Sign Up"
}

Example es-ES.json:

{
  "welcome_message": "¡Bienvenido a nuestra app!",
  "login_button": "Iniciar sesión",
  "signup_button": "Registrarse"
}

2. Wrap Your App with I18nProvider

The I18nProvider uses Yew's Suspense, so wrap it with a <Suspense> component to show a fallback while translations are loading.

use yew::prelude::*;
use yew_i18n::I18nProvider;

#[function_component(App)]
fn app() -> Html {
    html! {
        <Suspense fallback={html! { <p>{"Loading translations..."}</p> }}>
            <I18nProvider base_path="/static/language">
                <MyComponent />
            </I18nProvider>
        </Suspense>
    }
}

3. Use Translations in Components

use yew::prelude::*;
use yew_i18n::use_translation;

#[function_component(MyComponent)]
fn my_component() -> Html {
    let i18n = use_translation();

    html! {
        <div>
            <h1>{ i18n.t("welcome_message") }</h1>
            <button>{ i18n.t("login_button") }</button>
        </div>
    }
}

4. Change Language at Runtime

use yew::prelude::*;
use yew_i18n::{use_change_locale, Locale};

#[function_component(LanguageSwitcher)]
fn language_switcher() -> Html {
    let change_locale = use_change_locale();

    let on_english = {
        let change_locale = change_locale.clone();
        Callback::from(move |_| {
            change_locale.emit(Locale::EnglishUS);
        })
    };

    let on_spanish = {
        let change_locale = change_locale.clone();
        Callback::from(move |_| {
            change_locale.emit(Locale::SpanishES);
        })
    };

    html! {
        <div>
            <button onclick={on_english}>{ "English" }</button>
            <button onclick={on_spanish}>{ "Español" }</button>
        </div>
    }
}

API Reference

I18nProvider

Context provider component that loads and manages translations.

Props:

  • base_path: &'static str - Base path where translation JSON files are located (e.g., "/static/language")
  • children: Html - Child components
  • initial_locale: Option<Locale> - Optional locale override (defaults to browser detection)

use_translation()

Hook to access translation context in components.

Returns: UseReducerHandle<TranslationData>

Methods:

  • .t(key: &str) -> &str - Translate a key (zero-allocation)
  • .translate(key: &str) -> &str - Translate a key (same as .t())
  • .current_locale() -> Locale - Get current locale

use_change_locale()

Hook to get a callback for changing locale at runtime.

Returns: Callback<Locale> - A callback that accepts a Locale and changes the current locale

Usage:

let change_locale = use_change_locale();
change_locale.emit(Locale::SpanishES);

Locale

Enum representing supported locales.

Variants:

  • Locale::EnglishUS - English (United States) - "en-US"
  • Locale::SpanishES - Spanish (Spain) - "es-ES"

Methods:

  • .as_ref() -> &str - Get locale code (e.g., "en-US", "es-ES") via AsRef<str> trait
  • Locale::detect_from_browser() -> Locale - Detect from browser settings (with fallback logic)

Browser Language Detection

The library automatically detects the browser's language preference on initialization:

// Detects browser language
let locale = Locale::detect_from_browser();

// Override detection
<I18nProvider base_path="/static/language" initial_locale={Some(Locale::EnglishUS)}>
    // ...
</I18nProvider>

Dynamic Loading

Unlike other i18n solutions that embed translations at compile-time using include_str!, this library fetches JSON files dynamically using the browser's fetch API. This means:

  • Smaller initial bundle size
  • Easier to update translations without recompiling
  • Translations are loaded on-demand
  • Works like loading CSS or image assets

Clippy Configuration

This crate follows strict linting rules:

#![warn(clippy::all, clippy::pedantic, clippy::nursery)]

Migration from Static Translations

If you're migrating from static include_str! translations:

Before:

// contexts/language.rs
static ENGLISH_TRANSLATIONS: &str = include_str!("../../../static_resources/language/en.json");
static SPANISH_TRANSLATIONS: &str = include_str!("../../../static_resources/language/es.json");

impl Default for TranslationData {
    fn default() -> Self {
        // ... manual browser detection and loading
    }
}

After:

use yew_i18n::{I18nProvider, use_translation};

// In app.rs
html! {
    <I18nProvider base_path="/static/language">
        <YourApp />
    </I18nProvider>
}

// In components
let i18n = use_translation();
html! { <h1>{ i18n.t("key") }</h1> }
Commit count: 0

cargo fmt