commit 7524cfba1ee4fc18ce30379dd0f3b9bb25fbeb1b
parent b0aafce32e9fc4c1c7fde79ef5e285580da467e5
Author: triesap <tyson@radroots.org>
Date: Mon, 2 Feb 2026 16:07:11 +0000
app: localize logs page
- add message keys for log actions and filters
- localize status and error labels
- update support instructions strings
- regenerate i18n build artifacts
Diffstat:
7 files changed, 750 insertions(+), 37 deletions(-)
diff --git a/app/i18n/build/i18n.catalog.json b/app/i18n/build/i18n.catalog.json
@@ -566,6 +566,523 @@
}
},
{
+ "key": "app.logs.action.clear",
+ "id": 618410449,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.action.copy_dump",
+ "id": 4122246909,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.action.download_dump",
+ "id": 4154904867,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.action.refresh",
+ "id": 2946508119,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.content.aria",
+ "id": 495027300,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.dump.title",
+ "id": 1388485668,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.entries.title",
+ "id": 684273162,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.error.anchor_cast_failed",
+ "id": 2533250272,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.error.anchor_failed",
+ "id": 3154831416,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.error.blob_failed",
+ "id": 2801667274,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.error.copy_failed",
+ "id": 3247522700,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.error.copy_unavailable",
+ "id": 4141297599,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.error.document_unavailable",
+ "id": 1080722381,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.error.download_unavailable",
+ "id": 4264123149,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.error.url_failed",
+ "id": 2872906070,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.error.window_unavailable",
+ "id": 2350479185,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.filters.aria",
+ "id": 2416988381,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.filters.from_ms",
+ "id": 1695556959,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.filters.search_placeholder",
+ "id": 2459121539,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.filters.to_ms",
+ "id": 3879399801,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.level.all",
+ "id": 3715000598,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.level.debug",
+ "id": 2466649524,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.level.error",
+ "id": 135430264,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.level.info",
+ "id": 289833569,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.level.warn",
+ "id": 3186734388,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.pagination.aria",
+ "id": 887319320,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.pagination.next",
+ "id": 2509771422,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.pagination.prev",
+ "id": 3713405982,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.status.copy_ok",
+ "id": 4173530628,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.status.download_ok",
+ "id": 251408416,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.status.dump_empty",
+ "id": 3480269256,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.status.idle",
+ "id": 3608732267,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.status.loading",
+ "id": 2750762471,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.status.support_bundle_ready",
+ "id": 3166859448,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.status.support_copy_ok",
+ "id": 1839220955,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.summary.limit",
+ "id": 3457741666,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.summary.of",
+ "id": 2155553479,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.summary.page",
+ "id": 1355876668,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.summary.showing",
+ "id": 2923985603,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.support.button.bundle",
+ "id": 2889964186,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.support.button.copy_instructions",
+ "id": 3553383813,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.support.instructions.download",
+ "id": 483676330,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.support.instructions.notes",
+ "id": 3320932212,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.support.instructions.share",
+ "id": 1138860050,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.support.instructions.title",
+ "id": 3942736448,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.support.title",
+ "id": 1704291719,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
+ "key": "app.logs.title",
+ "id": 2765296598,
+ "args": [],
+ "features": {
+ "select": false,
+ "plural_cardinal": false,
+ "plural_ordinal": false,
+ "formatters": []
+ }
+ },
+ {
"key": "app.nav.home",
"id": 2360822558,
"args": [],
diff --git a/app/i18n/build/id_map.json b/app/i18n/build/id_map.json
@@ -50,6 +50,53 @@
"app.init.stage.idle": 1446931460,
"app.init.stage.ready": 4200712024,
"app.init.stage.storage": 1242977634,
+ "app.logs.action.clear": 618410449,
+ "app.logs.action.copy_dump": 4122246909,
+ "app.logs.action.download_dump": 4154904867,
+ "app.logs.action.refresh": 2946508119,
+ "app.logs.content.aria": 495027300,
+ "app.logs.dump.title": 1388485668,
+ "app.logs.entries.title": 684273162,
+ "app.logs.error.anchor_cast_failed": 2533250272,
+ "app.logs.error.anchor_failed": 3154831416,
+ "app.logs.error.blob_failed": 2801667274,
+ "app.logs.error.copy_failed": 3247522700,
+ "app.logs.error.copy_unavailable": 4141297599,
+ "app.logs.error.document_unavailable": 1080722381,
+ "app.logs.error.download_unavailable": 4264123149,
+ "app.logs.error.url_failed": 2872906070,
+ "app.logs.error.window_unavailable": 2350479185,
+ "app.logs.filters.aria": 2416988381,
+ "app.logs.filters.from_ms": 1695556959,
+ "app.logs.filters.search_placeholder": 2459121539,
+ "app.logs.filters.to_ms": 3879399801,
+ "app.logs.level.all": 3715000598,
+ "app.logs.level.debug": 2466649524,
+ "app.logs.level.error": 135430264,
+ "app.logs.level.info": 289833569,
+ "app.logs.level.warn": 3186734388,
+ "app.logs.pagination.aria": 887319320,
+ "app.logs.pagination.next": 2509771422,
+ "app.logs.pagination.prev": 3713405982,
+ "app.logs.status.copy_ok": 4173530628,
+ "app.logs.status.download_ok": 251408416,
+ "app.logs.status.dump_empty": 3480269256,
+ "app.logs.status.idle": 3608732267,
+ "app.logs.status.loading": 2750762471,
+ "app.logs.status.support_bundle_ready": 3166859448,
+ "app.logs.status.support_copy_ok": 1839220955,
+ "app.logs.summary.limit": 3457741666,
+ "app.logs.summary.of": 2155553479,
+ "app.logs.summary.page": 1355876668,
+ "app.logs.summary.showing": 2923985603,
+ "app.logs.support.button.bundle": 2889964186,
+ "app.logs.support.button.copy_instructions": 3553383813,
+ "app.logs.support.instructions.download": 483676330,
+ "app.logs.support.instructions.notes": 3320932212,
+ "app.logs.support.instructions.share": 1138860050,
+ "app.logs.support.instructions.title": 3942736448,
+ "app.logs.support.title": 1704291719,
+ "app.logs.title": 2765296598,
"app.nav.home": 2360822558,
"app.nav.logs": 952998791,
"app.nav.primary_aria": 3495744422,
diff --git a/app/i18n/build/id_map_hash b/app/i18n/build/id_map_hash
@@ -1 +1 @@
-sha256:4026e886da6d0000d936662b86f6674c3afe1a103ed9277e57de9195166abf48
+sha256:1402a9727c23f2b6b70fd54bcb04138b40bfe0f8a9b464bcce626d9f0b48517d
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:4026e886da6d0000d936662b86f6674c3afe1a103ed9277e57de9195166abf48","mf2_packs":{"en":{"kind":"base","url":"packs/en.mf2pack","hash":"sha256:2c500463fe1deac6b200df23c67892adaf68760182c370ff45d59f387758c36d","size":7347,"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:1402a9727c23f2b6b70fd54bcb04138b40bfe0f8a9b464bcce626d9f0b48517d","mf2_packs":{"en":{"kind":"base","url":"packs/en.mf2pack","hash":"sha256:95aaf5fadb5d1f0f26d4b59d43a96858bd7bceb60894b5f9e18e7b5f57632c95","size":9683,"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
@@ -201,6 +201,101 @@ app.setup.eula.acceptance.title = Acceptance of Terms
app.setup.eula.acceptance.body = By using our application, you signify your acceptance of this EULA. If you do not agree to this EULA, you may not use our application.
+# logs
+app.logs.title = logs
+
+app.logs.action.refresh = refresh
+
+app.logs.action.clear = clear
+
+app.logs.action.copy_dump = copy dump
+
+app.logs.action.download_dump = download dump
+
+app.logs.status.idle = idle
+
+app.logs.status.loading = loading
+
+app.logs.status.dump_empty = dump empty
+
+app.logs.status.copy_ok = copied
+
+app.logs.status.download_ok = download ready
+
+app.logs.status.support_copy_ok = instructions copied
+
+app.logs.status.support_bundle_ready = support bundle ready
+
+app.logs.error.copy_unavailable = copy unavailable
+
+app.logs.error.copy_failed = copy failed
+
+app.logs.error.window_unavailable = window unavailable
+
+app.logs.error.download_unavailable = download unavailable
+
+app.logs.error.document_unavailable = document unavailable
+
+app.logs.error.blob_failed = blob creation failed
+
+app.logs.error.url_failed = url creation failed
+
+app.logs.error.anchor_failed = anchor creation failed
+
+app.logs.error.anchor_cast_failed = anchor cast failed
+
+app.logs.filters.aria = filters
+
+app.logs.filters.search_placeholder = search code/message/context
+
+app.logs.filters.from_ms = from ms
+
+app.logs.filters.to_ms = to ms
+
+app.logs.level.all = all
+
+app.logs.level.debug = debug
+
+app.logs.level.info = info
+
+app.logs.level.warn = warn
+
+app.logs.level.error = error
+
+app.logs.summary.showing = showing
+
+app.logs.summary.of = of
+
+app.logs.summary.limit = limit
+
+app.logs.summary.page = page
+
+app.logs.pagination.aria = pagination
+
+app.logs.pagination.prev = prev
+
+app.logs.pagination.next = next
+
+app.logs.support.button.bundle = support bundle
+
+app.logs.support.button.copy_instructions = copy instructions
+
+app.logs.content.aria = log content
+
+app.logs.entries.title = entries
+
+app.logs.dump.title = dump (jsonl)
+
+app.logs.support.title = support instructions
+
+app.logs.support.instructions.title = support bundle
+
+app.logs.support.instructions.download = 1) download the log dump jsonl file
+
+app.logs.support.instructions.share = 2) share the file with support
+
+app.logs.support.instructions.notes = 3) include notes about the issue and time window
+
# errors
error.app.init.idb = storage unavailable
diff --git a/app/src/logs.rs b/app/src/logs.rs
@@ -27,6 +27,7 @@ use crate::{
RadrootsAppLogEntry,
RadrootsAppLogLevel,
};
+use crate::t;
#[cfg(target_arch = "wasm32")]
use js_sys::Array;
@@ -60,6 +61,28 @@ fn log_level_color(level: RadrootsAppLogLevel) -> &'static str {
}
}
+fn log_status_label(value: &str) -> String {
+ match value {
+ "idle" => t!("app.logs.status.idle"),
+ "loading" => t!("app.logs.status.loading"),
+ "dump_empty" => t!("app.logs.status.dump_empty"),
+ "copy_ok" => t!("app.logs.status.copy_ok"),
+ "download_ok" => t!("app.logs.status.download_ok"),
+ "support_copy_ok" => t!("app.logs.status.support_copy_ok"),
+ "support_bundle_ready" => t!("app.logs.status.support_bundle_ready"),
+ "copy_unavailable" => t!("app.logs.error.copy_unavailable"),
+ "copy_failed" => t!("app.logs.error.copy_failed"),
+ "window_unavailable" => t!("app.logs.error.window_unavailable"),
+ "download_unavailable" => t!("app.logs.error.download_unavailable"),
+ "document_unavailable" => t!("app.logs.error.document_unavailable"),
+ "blob_failed" => t!("app.logs.error.blob_failed"),
+ "url_failed" => t!("app.logs.error.url_failed"),
+ "anchor_failed" => t!("app.logs.error.anchor_failed"),
+ "anchor_cast_failed" => t!("app.logs.error.anchor_cast_failed"),
+ _ => value.to_string(),
+ }
+}
+
fn log_level_matches(level: RadrootsAppLogLevel, filter: &str) -> bool {
if filter.is_empty() || filter == "all" {
return true;
@@ -211,10 +234,10 @@ fn log_dump_with_context(entries: &[RadrootsAppLogEntry], header: String) -> Str
fn support_instructions_text() -> String {
let lines = [
- "support bundle",
- "1) download the log dump jsonl file",
- "2) share the file with support",
- "3) include notes about the issue and time window",
+ t!("app.logs.support.instructions.title"),
+ t!("app.logs.support.instructions.download"),
+ t!("app.logs.support.instructions.share"),
+ t!("app.logs.support.instructions.notes"),
];
lines.join("\n")
}
@@ -558,12 +581,28 @@ pub fn RadrootsAppLogsPage() -> impl IntoView {
});
on_cleanup(move || abort_handle_cleanup.abort());
});
- let status_label = move || if loading.get() { "loading" } else { "idle" };
- let dump_action_label =
- move || dump_status.get().unwrap_or_else(|| "idle".to_string());
+ let status_label = move || {
+ if loading.get() {
+ t!("app.logs.status.loading")
+ } else {
+ t!("app.logs.status.idle")
+ }
+ };
+ let dump_action_label = move || {
+ dump_status
+ .get()
+ .as_deref()
+ .map(log_status_label)
+ .unwrap_or_else(|| t!("app.logs.status.idle"))
+ };
let dump_action_disabled = move || dump_action_running.get();
- let support_label =
- move || support_status.get().unwrap_or_else(|| "idle".to_string());
+ let support_label = move || {
+ support_status
+ .get()
+ .as_deref()
+ .map(log_status_label)
+ .unwrap_or_else(|| t!("app.logs.status.idle"))
+ };
let support_disabled = move || support_running.get();
let prev_disabled = move || page_index.get() == 0;
let next_disabled = move || {
@@ -573,18 +612,18 @@ pub fn RadrootsAppLogsPage() -> impl IntoView {
view! {
<main id="app-logs" class="app-page app-page-scroll">
<header id="app-logs-header" style="display:flex;align-items:center;gap:12px;">
- <h1 id="app-logs-title" style="font-size:18px;font-weight:600;">"logs"</h1>
- <button on:click=move |_| refresh()>"refresh"</button>
- <button on:click=move |_| clear()>"clear"</button>
- <button on:click=move |_| copy_dump() disabled=dump_action_disabled>"copy dump"</button>
- <button on:click=move |_| download_dump() disabled=dump_action_disabled>"download dump"</button>
+ <h1 id="app-logs-title" style="font-size:18px;font-weight:600;">{t!("app.logs.title")}</h1>
+ <button on:click=move |_| refresh()>{t!("app.logs.action.refresh")}</button>
+ <button on:click=move |_| clear()>{t!("app.logs.action.clear")}</button>
+ <button on:click=move |_| copy_dump() disabled=dump_action_disabled>{t!("app.logs.action.copy_dump")}</button>
+ <button on:click=move |_| download_dump() disabled=dump_action_disabled>{t!("app.logs.action.download_dump")}</button>
<div id="app-logs-status" style="font-size:12px;color:#6b7280;">{status_label}</div>
<div id="app-logs-dump-status" style="font-size:12px;color:#6b7280;">{dump_action_label}</div>
</header>
- <section id="app-logs-filters" aria-label="Filters" style="margin-top:12px;display:flex;flex-wrap:wrap;gap:12px;align-items:center;">
+ <section id="app-logs-filters" aria-label=t!("app.logs.filters.aria") style="margin-top:12px;display:flex;flex-wrap:wrap;gap:12px;align-items:center;">
<input
type="text"
- placeholder="search code/message/context"
+ placeholder=t!("app.logs.filters.search_placeholder")
prop:value=move || filter_query.get()
on:input=move |ev| {
filter_query.set(event_target_value(&ev));
@@ -598,15 +637,15 @@ pub fn RadrootsAppLogsPage() -> impl IntoView {
}
style="border:1px solid #e5e7eb;border-radius:8px;padding:6px 8px;font-size:12px;"
>
- <option value="all">"all"</option>
- <option value="debug">"debug"</option>
- <option value="info">"info"</option>
- <option value="warn">"warn"</option>
- <option value="error">"error"</option>
+ <option value="all">{t!("app.logs.level.all")}</option>
+ <option value="debug">{t!("app.logs.level.debug")}</option>
+ <option value="info">{t!("app.logs.level.info")}</option>
+ <option value="warn">{t!("app.logs.level.warn")}</option>
+ <option value="error">{t!("app.logs.level.error")}</option>
</select>
<input
type="number"
- placeholder="from ms"
+ placeholder=t!("app.logs.filters.from_ms")
prop:value=move || filter_from.get()
on:input=move |ev| {
filter_from.set(event_target_value(&ev));
@@ -615,7 +654,7 @@ pub fn RadrootsAppLogsPage() -> impl IntoView {
/>
<input
type="number"
- placeholder="to ms"
+ placeholder=t!("app.logs.filters.to_ms")
prop:value=move || filter_to.get()
on:input=move |ev| {
filter_to.set(event_target_value(&ev));
@@ -644,11 +683,22 @@ pub fn RadrootsAppLogsPage() -> impl IntoView {
let limit = filter_limit.get();
let pages = page_total.get();
let page = if pages == 0 { 0 } else { page_index.get() + 1 };
- format!("showing {visible} of {total} (limit {limit}) page {page}/{pages}")
+ format!(
+ "{} {} {} {} ({} {}) {} {}/{}",
+ t!("app.logs.summary.showing"),
+ visible,
+ t!("app.logs.summary.of"),
+ total,
+ t!("app.logs.summary.limit"),
+ limit,
+ t!("app.logs.summary.page"),
+ page,
+ pages
+ )
}}
</div>
</section>
- <section id="app-logs-pagination" aria-label="Pagination" style="margin-top:8px;display:flex;align-items:center;gap:8px;">
+ <section id="app-logs-pagination" aria-label=t!("app.logs.pagination.aria") style="margin-top:8px;display:flex;align-items:center;gap:8px;">
<button
on:click=move |_| {
let next = page_index.get().saturating_sub(1);
@@ -656,7 +706,7 @@ pub fn RadrootsAppLogsPage() -> impl IntoView {
}
disabled=prev_disabled
>
- "prev"
+ {t!("app.logs.pagination.prev")}
</button>
<button
on:click=move |_| {
@@ -665,19 +715,19 @@ pub fn RadrootsAppLogsPage() -> impl IntoView {
}
disabled=next_disabled
>
- "next"
+ {t!("app.logs.pagination.next")}
</button>
<button on:click=move |_| support_bundle() disabled=support_disabled>
- "support bundle"
+ {t!("app.logs.support.button.bundle")}
</button>
<button on:click=move |_| copy_support() disabled=support_disabled>
- "copy instructions"
+ {t!("app.logs.support.button.copy_instructions")}
</button>
<div id="app-logs-support-status" style="font-size:12px;color:#6b7280;">{support_label}</div>
</section>
- <section id="app-logs-content" aria-label="Log content" style="margin-top:12px;display:flex;flex-wrap:wrap;gap:16px;">
+ <section id="app-logs-content" aria-label=t!("app.logs.content.aria") style="margin-top:12px;display:flex;flex-wrap:wrap;gap:16px;">
<section id="app-logs-entries" style="flex:1 1 520px;min-width:280px;">
- <h2 id="app-logs-entries-title" style="font-weight:600;font-size:14px;">"entries"</h2>
+ <h2 id="app-logs-entries-title" style="font-weight:600;font-size:14px;">{t!("app.logs.entries.title")}</h2>
<div id="app-logs-entries-list" style="margin-top:8px;border:1px solid #e5e7eb;border-radius:8px;height:60vh;overflow:auto;padding:10px;display:flex;flex-direction:column;gap:10px;">
<For
each=move || paged_entries.get()
@@ -723,13 +773,13 @@ pub fn RadrootsAppLogsPage() -> impl IntoView {
</div>
</section>
<section id="app-logs-dump" style="flex:1 1 320px;min-width:260px;">
- <h2 id="app-logs-dump-title" style="font-weight:600;font-size:14px;">"dump (jsonl)"</h2>
+ <h2 id="app-logs-dump-title" style="font-weight:600;font-size:14px;">{t!("app.logs.dump.title")}</h2>
<textarea
readonly
prop:value=move || dump_text.get()
style="margin-top:8px;width:100%;height:60vh;border:1px solid #e5e7eb;border-radius:8px;padding:8px;font-size:12px;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace;"
></textarea>
- <h3 id="app-logs-support-title" style="margin-top:12px;font-weight:600;font-size:14px;">"support instructions"</h3>
+ <h3 id="app-logs-support-title" style="margin-top:12px;font-weight:600;font-size:14px;">{t!("app.logs.support.title")}</h3>
<textarea
readonly
prop:value=move || support_instructions_text()
@@ -761,7 +811,8 @@ mod tests {
logs_max_visible,
logs_page_size_default,
};
- use crate::{RadrootsAppLogEntry, RadrootsAppLogLevel, RadrootsAppLogMetadata};
+ use crate::{app_i18n_init, RadrootsAppLogEntry, RadrootsAppLogLevel, RadrootsAppLogMetadata};
+ use leptos::prelude::{provide_context, Owner};
#[test]
fn logs_auto_refresh_is_positive() {
@@ -890,6 +941,9 @@ mod tests {
#[test]
fn support_instructions_are_present() {
+ let owner = Owner::new();
+ owner.set();
+ provide_context(app_i18n_init());
let text = support_instructions_text();
assert!(text.contains("support bundle"));
}