From hackartist-plugins
This skill should be used when the user asks to "add i18n", "add translations", "create an i18n.rs file", "translate this component", "add Korean/English text", "use dioxus-translate", "add a translate! macro", "derive Translate", "switch language", or works with multi-language UI text in a Dioxus (Rust) application. Covers the translate! macro, Translate derive for enums, use_translate/use_language hooks, and language switching/persistence.
How this skill is triggered — by the user, by Claude, or both
Slash command
/hackartist-plugins:dioxus-translateThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
dioxus-translate is a Rust i18n library for the Dioxus framework. It generates type-safe
dioxus-translate is a Rust i18n library for the Dioxus framework. It generates type-safe
translation structs at compile time, so every UI string is a checked struct field rather
than a runtime string key. It supports English (en, always on) and Korean (ko, behind
the ko cargo feature), works on web (wasm), SSR/fullstack, and native (desktop/mobile)
targets, and persists the user's language choice via localStorage and a language cookie.
Three crates work together (typically only dioxus-translate is imported directly):
| Crate | Provides |
|---|---|
dioxus-translate | Language enum, use_translate(), use_language(), set_language(), translate::<T>() |
dioxus-translate-macro | translate! function-like macro, #[derive(Translate)] for enums |
dioxus-translate-types | Translator trait (fn en() -> Self, fn ko() -> Self) |
Two distinct mechanisms:
translate! macro — generates a struct of &'static str fields for component UI text.
Used in per-page/per-feature i18n.rs files. Consumed via use_translate().#[derive(Translate)] — implements fn translate(&self, lang: &Language) -> &'static str
on an enum. Used for error enums and option/label enums (e.g. roles, statuses).Add to Cargo.toml (enable ko for Korean support):
[dependencies]
dioxus-translate = { version = "0.1", features = ["ko"] }
Without the ko feature, Language::Ko and all ko: translations are compiled out and
only English exists. Conditional code touching Language::Ko must be gated with
#[cfg(feature = "ko")] when the consuming crate forwards the feature.
translate!i18n.rs next to the componentConvention: each page/feature directory owns an i18n.rs declaring one or more
*Translate structs named after the component (e.g. HomeTranslate, NotificationsTranslate).
use dioxus_translate::*;
translate! {
NotificationsTranslate;
panel_title: { en: "Notifications", ko: "알림" },
mark_all_read: { en: "Mark all as read", ko: "모두 읽음" },
empty: { en: "No notifications yet", ko: "새 알림이 없습니다" },
reply_title: { en: "{name} replied to your comment", ko: "{name}님이 답글을 남겼습니다" },
}
Syntax rules:
;.field_name: { en: "...", ko: "..." }, — trailing commas allowed.pub field_name: &'static str.{placeholder} tokens are plain text — interpolate at the call site with .replace().The macro expands to a pub struct with #[derive(Debug, Clone, PartialEq)], a
new(lang: &Language) -> Self constructor, and a Translator impl (en()/ko()).
use_translate()use dioxus_translate::*;
#[component]
pub fn NotificationPanel() -> Element {
let tr: NotificationsTranslate = use_translate();
rsx! {
div { class: "panel",
h2 { "{tr.panel_title}" }
button { "{tr.mark_all_read}" }
}
}
}
use_translate() is reactive: it reads the global language signal, so components re-render
on language change. The local binding is conventionally named tr.
.replace()There is no built-in interpolation. Fields are &'static str; substitute manually:
let title = tr.reply_title.replace("{name}", &user_name);
#[derive(Translate)]For error enums and selectable-option enums, derive Translate and annotate variants:
use dioxus_translate::Translate;
use thiserror::Error;
#[derive(Debug, Error, Serialize, Deserialize, Translate, Clone)]
pub enum NotificationsError {
#[error("inbox entry not found")]
#[translate(en = "Notification not found", ko = "알림을 찾을 수 없습니다")]
InboxEntryNotFound,
#[error("mark-read failed")]
#[translate(en = "Failed to mark as read", ko = "읽음 처리에 실패했습니다")]
MarkReadFailed,
}
Usage: err.translate(&lang) returns the localized &'static str.
Key behaviors:
#[translate(...)] fall back to the variant name as the English string.{ .. }), and tuple ((..)) variants.#[translate(from)] on a single-field tuple variant delegates to the inner type's
Translate impl — useful for nested error enums:
#[error("{0}")]
#[translate(from)]
SpaceReward(#[from] SpaceRewardError),
EnumName::VARIANTS (unit variants only) and
EnumName::variants(&lang) -> Vec<String> — handy for populating <select> options.use dioxus_translate::{use_language, set_language, Language};
let lang = use_language(); // Signal<Language>; read with lang()
let current: Language = lang();
set_language(Language::Ko); // set explicitly (e.g. settings panel buttons)
let next = current.switch(); // toggle En <-> Ko; persists to localStorage + cookie
Language::switch() flips the language, writes localStorage["language"], and sets a
language=<code>; path=/ cookie (web only) so SSR renders the right language.set_language() only updates the signal; pair with persistence when needed.set_initial_language(lang) restores a saved preference at app startup (native/desktop
targets hydrate from WebView localStorage before first render).lang.to_string() / "ko".parse::<Language>() convert to/from "en"/"ko" codes;
unknown codes parse as En.On non-wasm targets, use_language() detects context at runtime: during an HTTP render it
reads the language cookie from the request (language_from_cookie()); on a native client
it uses the global signal. No app code changes are required — just be aware the cookie set
by switch() is what makes server-rendered HTML match the client language.
Outside components (helpers, services), construct a translation struct directly:
let tr = NotificationsTranslate::new(&lang); // from a Language value
let tr: NotificationsTranslate = translate(&lang); // equivalent free function
Pass &tr and/or &lang into plain helper functions rather than calling hooks there.
i18n.rs per page/feature directory; struct named <Component>Translate.let tr: XxxTranslate = use_translate(); at the top of the component.panel_title, empty, save_button).{curly_braces}, resolved with chained .replace() calls.types/error.rs combining thiserror::Error + Translate so the
same enum yields log messages (#[error]) and user-facing localized text (#[translate]).references/api-reference.md — complete API surface: Language methods, hook
signatures, macro expansion details, feature flags, SSR/cookie internals.examples/i18n.rs — a complete translate! i18n module with placeholders.examples/component.rs — component consuming translations, interpolation helper.examples/error_enum.rs — #[derive(Translate)] error enum with from delegation.examples/language_switcher.rs — settings-panel language selector using set_language.npx claudepluginhub hackartists/plugin --plugin hackartistCreates bite-sized, testable implementation plans from specs or requirements, with file structure and task decomposition. Activates before coding multi-step tasks.