commit 2724e4532abd1abb9b3be0fb641067dcd3b51a0f
parent d46b0c64370ec4e101c6a90c3a73e79e22e2baa7
Author: triesap <tyson@radroots.org>
Date: Mon, 2 Feb 2026 15:36:21 +0000
app: localize setup flow
- add setup intro, key choice, and profile messages
- translate farmer choice labels and setup prompts
- localize setup navigation and confirm copy
- regenerate mf2-i18n build artifacts
Diffstat:
7 files changed, 279 insertions(+), 28 deletions(-)
diff --git a/app/i18n/build/i18n.catalog.json b/app/i18n/build/i18n.catalog.json
@@ -5,6 +5,28 @@
"default_locale": "en",
"messages": [
{
+ "key": "app.common.back",
+ "id": 2990764910,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.common.continue",
+ "id": 385087683,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
"key": "app.common.missing",
"id": 3520194192,
"args": [],
@@ -16,6 +38,17 @@
}
},
{
+ "key": "app.common.no",
+ "id": 1027581146,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
"key": "app.common.unknown",
"id": 1588621956,
"args": [],
@@ -27,6 +60,17 @@
}
},
{
+ "key": "app.common.yes",
+ "id": 1057379348,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
"key": "app.home.health.aria",
"id": 3172671582,
"args": [],
@@ -577,6 +621,160 @@
}
},
{
+ "key": "app.setup.farmer.title",
+ "id": 3967778278,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.setup.intro.body",
+ "id": 3075641340,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.setup.intro.kicker",
+ "id": 397915792,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.setup.intro.welcome",
+ "id": 909038201,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.setup.key_add.placeholder",
+ "id": 728766925,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.setup.key_add.title",
+ "id": 3229091810,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.setup.key_choice.create",
+ "id": 963716841,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.setup.key_choice.title",
+ "id": 2829853649,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.setup.key_choice.use_existing",
+ "id": 3945623834,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.setup.profile.confirm_no_name",
+ "id": 420411302,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.setup.profile.nip05.prefix",
+ "id": 3344734641,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.setup.profile.nip05.suffix",
+ "id": 853057844,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.setup.profile.placeholder",
+ "id": 321152177,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.setup.profile.title",
+ "id": 103377718,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
"key": "error.app.init.assets",
"id": 172100683,
"args": [],
diff --git a/app/i18n/build/id_map.json b/app/i18n/build/id_map.json
@@ -1,6 +1,10 @@
{
+ "app.common.back": 2990764910,
+ "app.common.continue": 385087683,
"app.common.missing": 3520194192,
+ "app.common.no": 1027581146,
"app.common.unknown": 1588621956,
+ "app.common.yes": 1057379348,
"app.home.health.aria": 3172671582,
"app.home.health.button.checking": 3465392175,
"app.home.health.button.run": 1230595839,
@@ -51,6 +55,20 @@
"app.nav.setup": 2066290074,
"app.nav.ui": 2416341108,
"app.not_found": 3182331848,
+ "app.setup.farmer.title": 3967778278,
+ "app.setup.intro.body": 3075641340,
+ "app.setup.intro.kicker": 397915792,
+ "app.setup.intro.welcome": 909038201,
+ "app.setup.key_add.placeholder": 728766925,
+ "app.setup.key_add.title": 3229091810,
+ "app.setup.key_choice.create": 963716841,
+ "app.setup.key_choice.title": 2829853649,
+ "app.setup.key_choice.use_existing": 3945623834,
+ "app.setup.profile.confirm_no_name": 420411302,
+ "app.setup.profile.nip05.prefix": 3344734641,
+ "app.setup.profile.nip05.suffix": 853057844,
+ "app.setup.profile.placeholder": 321152177,
+ "app.setup.profile.title": 103377718,
"error.app.init.assets": 172100683,
"error.app.init.config": 3737196850,
"error.app.init.datastore": 1124445179,
diff --git a/app/i18n/build/id_map_hash b/app/i18n/build/id_map_hash
@@ -1 +1 @@
-sha256:6f697fe6b69bf95389c0703cd551d61fecee1f5607ad76520d10390781027b82
+sha256:bbf87cb3cd423c088f4002810c7cc87b8a2d251e6b76d4e71cdf02b5e4d84b08
diff --git a/app/i18n/build/manifest.json b/app/i18n/build/manifest.json
@@ -1 +1 @@
-{"schema":1,"release_id":"dev","generated_at":"2026-02-02T00:00:00Z","default_locale":"en","supported_locales":["en"],"id_map_hash":"sha256:6f697fe6b69bf95389c0703cd551d61fecee1f5607ad76520d10390781027b82","mf2_packs":{"en":{"kind":"base","url":"packs/en.mf2pack","hash":"sha256:8c7a60157aafe3fc9a5acb3725cf5a748eea3a252839eb1e4aa87ddb8ad86f31","size":3182,"content_encoding":"identity","pack_schema":0}}}
-\ No newline at end of file
+{"schema":1,"release_id":"dev","generated_at":"2026-02-02T00:00:00Z","default_locale":"en","supported_locales":["en"],"id_map_hash":"sha256:bbf87cb3cd423c088f4002810c7cc87b8a2d251e6b76d4e71cdf02b5e4d84b08","mf2_packs":{"en":{"kind":"base","url":"packs/en.mf2pack","hash":"sha256:91a973fb93cd33c3122aefe92ebf98976e720a07eced81f074ad2b80e2516c22","size":4210,"content_encoding":"identity","pack_schema":0}}}
+\ No newline at end of file
diff --git a/app/i18n/build/packs/en.mf2pack b/app/i18n/build/packs/en.mf2pack
Binary files differ.
diff --git a/app/i18n/locales/en/messages.mf2 b/app/i18n/locales/en/messages.mf2
@@ -3,6 +3,14 @@ app.common.missing = missing
app.common.unknown = unknown
+app.common.back = Back
+
+app.common.continue = Continue
+
+app.common.no = No
+
+app.common.yes = Yes
+
# nav
app.nav.primary_aria = primary
@@ -107,6 +115,35 @@ app.home.health.message.uninitialized = uninitialized
app.home.health.message.unavailable = unavailable
+# setup
+app.setup.intro.kicker = Configure
+
+app.setup.intro.welcome = Welcome to Radroots!
+
+app.setup.intro.body = Your device will be configured by the setup wizard.
+
+app.setup.key_choice.title = Configure Device
+
+app.setup.key_choice.create = Create new keypair
+
+app.setup.key_choice.use_existing = Use existing keypair
+
+app.setup.key_add.title = Add existing key
+
+app.setup.key_add.placeholder = Enter nostr nsec/hex
+
+app.setup.profile.title = Add Profile
+
+app.setup.profile.placeholder = Enter profile name
+
+app.setup.profile.nip05.prefix = Create
+
+app.setup.profile.nip05.suffix = NIP-05 address
+
+app.setup.profile.confirm_no_name = Your profile will be created without a name. You can change this later in Settings > Profile
+
+app.setup.farmer.title = Setup for Farmer
+
# errors
error.app.init.idb = storage unavailable
diff --git a/app/src/app.rs b/app/src/app.rs
@@ -253,9 +253,6 @@ fn spawn_health_checks(
}
const APP_HEALTH_CHECK_DELAY_MS: u32 = 300;
-const APP_SETUP_NO_PROFILE_NAME_CONFIRM: &str =
- "Your profile will be created without a name. You can change this later in Settings > Profile";
-
fn app_health_check_delay_ms() -> u32 {
APP_HEALTH_CHECK_DELAY_MS
}
@@ -518,11 +515,10 @@ fn SetupPage() -> impl IntoView {
let profile_name = profile_name.get();
if profile_name.trim().is_empty() {
let setup_step = setup_step.clone();
+ let confirm_message = t!("app.setup.profile.confirm_no_name");
spawn_local(async move {
let notifications = RadrootsAppNotifications::new(None);
- let confirm = notifications
- .confirm_message(APP_SETUP_NO_PROFILE_NAME_CONFIRM)
- .await;
+ let confirm = notifications.confirm_message(&confirm_message).await;
if confirm {
setup_step.set(RadrootsAppSetupStep::FarmerSetup);
}
@@ -637,7 +633,7 @@ fn SetupPage() -> impl IntoView {
id="app-setup-intro-kicker"
class="w-full text-left font-sans font-[400] text-sm uppercase text-ly0-gl-label"
>
- "Configure"
+ {t!("app.setup.intro.kicker")}
</p>
<div
id="app-setup-intro-copy"
@@ -647,13 +643,13 @@ fn SetupPage() -> impl IntoView {
id="app-setup-intro-line-welcome"
class="w-full text-left font-mono font-[400] text-[1.1rem] text-ly0-gl"
>
- "Welcome to Radroots!"
+ {t!("app.setup.intro.welcome")}
</p>
<p
id="app-setup-intro-line-body"
class="w-full text-left font-mono font-[400] text-[1.1rem] text-ly0-gl"
>
- "Your device will be configured by the setup wizard."
+ {t!("app.setup.intro.body")}
</p>
</div>
</footer>
@@ -680,7 +676,7 @@ fn SetupPage() -> impl IntoView {
class="flex flex-row w-full justify-center items-center"
>
<p class="font-sans font-[600] text-ly0-gl text-3xl">
- "Configure Device"
+ {t!("app.setup.key_choice.title")}
</p>
</div>
<div
@@ -706,7 +702,7 @@ fn SetupPage() -> impl IntoView {
}
>
<span class="font-sans font-[600] text-ly0-gl text-xl">
- "Create new keypair"
+ {t!("app.setup.key_choice.create")}
</span>
</button>
<button
@@ -728,7 +724,7 @@ fn SetupPage() -> impl IntoView {
}
>
<span class="font-sans font-[600] text-ly0-gl text-xl">
- "Use existing keypair"
+ {t!("app.setup.key_choice.use_existing")}
</span>
</button>
</div>
@@ -752,13 +748,13 @@ fn SetupPage() -> impl IntoView {
id="app-setup-key-add-existing-title"
class="font-sans font-[600] text-ly0-gl text-3xl capitalize"
>
- "Add existing key"
+ {t!("app.setup.key_add.title")}
</p>
<input
id="app-setup-key-add-existing-input"
class="input-base w-lo_ios0 ios1:w-lo_ios1 text-[1.25rem] text-center placeholder:opacity-60"
type="text"
- placeholder="Enter nostr nsec/hex"
+ placeholder=t!("app.setup.key_add.placeholder")
prop:value=move || nostr_key_add.get()
on:input=move |ev| {
nostr_key_add.set(event_target_value(&ev));
@@ -785,7 +781,7 @@ fn SetupPage() -> impl IntoView {
id="app-setup-profile-title"
class="font-sans font-[600] text-ly0-gl text-3xl"
>
- "Add Profile"
+ {t!("app.setup.profile.title")}
</p>
<div
id="app-setup-profile-fields"
@@ -795,7 +791,7 @@ fn SetupPage() -> impl IntoView {
id="app-setup-profile-name"
class="input-base w-lo_ios0 ios1:w-lo_ios1 text-[1.25rem] text-center placeholder:opacity-60"
type="text"
- placeholder="Enter profile name"
+ placeholder=t!("app.setup.profile.placeholder")
prop:value=move || profile_name.get()
on:keydown=move |ev: KeyboardEvent| {
if ev.key() == "Enter" {
@@ -824,11 +820,13 @@ fn SetupPage() -> impl IntoView {
class="flex flex-row justify-center items-center"
>
<span class="font-sans font-[400] text-ly0-gl text-[14px] tracking-wide">
- "Create "
+ {t!("app.setup.profile.nip05.prefix")}
+ {" "}
<span class="font-mono font-[500] tracking-tight px-[3px]">
"@radroots"
</span>
- " NIP-05 address"
+ {" "}
+ {t!("app.setup.profile.nip05.suffix")}
</span>
</label>
</div>
@@ -858,7 +856,7 @@ fn SetupPage() -> impl IntoView {
class="flex flex-row w-full justify-center items-center"
>
<p class="font-sans font-[600] text-ly0-gl text-3xl">
- "Setup for Farmer"
+ {t!("app.setup.farmer.title")}
</p>
</div>
<div
@@ -883,7 +881,7 @@ fn SetupPage() -> impl IntoView {
}
>
<span class="font-sans font-[600] text-ly0-gl text-xl">
- "Yes"
+ {t!("app.common.yes")}
</span>
</button>
<button
@@ -904,7 +902,7 @@ fn SetupPage() -> impl IntoView {
}
>
<span class="font-sans font-[600] text-ly0-gl text-xl">
- "No"
+ {t!("app.common.no")}
</span>
</button>
</div>
@@ -1118,17 +1116,17 @@ fn SetupPage() -> impl IntoView {
&& setup_key_choice.get().is_none())
|| (matches!(step, RadrootsAppSetupStep::FarmerSetup)
&& setup_farmer_choice.get().is_none());
- let continue_label = "Continue";
- let back_label = "Back";
+ let continue_label = t!("app.common.continue");
+ let back_label = t!("app.common.back");
let continue_action = RadrootsAppUiButtonLayoutAction {
- label: continue_label.to_string(),
+ label: continue_label,
disabled: continue_disabled,
loading: false,
on_click: advance_step_click.clone(),
};
let back_action = RadrootsAppUiButtonLayoutBackAction {
visible: !matches!(step, RadrootsAppSetupStep::Intro),
- label: Some(back_label.to_string()),
+ label: Some(back_label),
disabled: false,
on_click: rewind_step.clone(),
};