diff --git a/app/src/main/java/com/m57/hermescontrol/ui/logs/LogsScreen.kt b/app/src/main/java/com/m57/hermescontrol/ui/logs/LogsScreen.kt
index 0c7b37e7..51ea9a49 100644
--- a/app/src/main/java/com/m57/hermescontrol/ui/logs/LogsScreen.kt
+++ b/app/src/main/java/com/m57/hermescontrol/ui/logs/LogsScreen.kt
@@ -18,11 +18,13 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
+import com.m57.hermescontrol.R
import com.m57.hermescontrol.theme.LocalSpacing
import com.m57.hermescontrol.ui.common.EmptyState
import com.m57.hermescontrol.ui.common.ErrorState
@@ -59,7 +61,7 @@ fun LogsScreen(
}
HermesScaffold(
- title = { Text("Logs") },
+ title = { Text(stringResource(R.string.screen_logs)) },
onOpenDrawer = onOpenDrawer,
isRefreshing = state.isLoading,
onRefresh = { viewModel.loadLogs() },
@@ -71,7 +73,7 @@ fun LogsScreen(
state.errorMessage != null -> {
ErrorState(
- message = state.errorMessage ?: "Unknown error",
+ message = state.errorMessage ?: stringResource(R.string.error_unknown),
onRetry = { viewModel.loadLogs() },
)
}
@@ -80,8 +82,8 @@ fun LogsScreen(
// B5 (Jun 18 2026, kanban t_2322818d): proper empty-state using
// the shared EmptyState component instead of a bare Text.
EmptyState(
- title = "No logs available",
- subtitle = "Log output from Hermes will appear here.",
+ title = stringResource(R.string.logs_empty_title),
+ subtitle = stringResource(R.string.logs_empty_desc),
icon = Icons.Filled.HistoryEdu,
)
}
diff --git a/app/src/main/java/com/m57/hermescontrol/ui/model/ModelScreen.kt b/app/src/main/java/com/m57/hermescontrol/ui/model/ModelScreen.kt
index 8efb7d36..27036d4a 100644
--- a/app/src/main/java/com/m57/hermescontrol/ui/model/ModelScreen.kt
+++ b/app/src/main/java/com/m57/hermescontrol/ui/model/ModelScreen.kt
@@ -35,10 +35,12 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
+import com.m57.hermescontrol.R
import com.m57.hermescontrol.ui.common.EmptyState
import com.m57.hermescontrol.ui.common.ErrorState
import com.m57.hermescontrol.ui.common.HermesScaffold
@@ -67,7 +69,7 @@ fun ModelScreen(
}
HermesScaffold(
- title = { Text("Models") },
+ title = { Text(stringResource(R.string.screen_models)) },
onOpenDrawer = onOpenDrawer,
isRefreshing = state.isLoading,
onRefresh = { viewModel.loadModelOptions() },
@@ -87,10 +89,10 @@ fun ModelScreen(
state.providers.isEmpty() -> {
EmptyState(
- title = "No model providers reported",
- subtitle = "Verify configuration or retry",
+ title = stringResource(R.string.model_empty_title),
+ subtitle = stringResource(R.string.model_empty_desc),
onAction = { viewModel.loadModelOptions() },
- actionLabel = "Refresh",
+ actionLabel = stringResource(R.string.content_desc_refresh),
modifier = Modifier.padding(paddingValues),
)
}
@@ -107,7 +109,10 @@ fun ModelScreen(
Text(text = state.errorMessage ?: "", color = MaterialTheme.colorScheme.error)
Spacer(modifier = Modifier.height(16.dp))
IconButton(onClick = { viewModel.loadModelOptions() }) {
- Icon(imageVector = Icons.Filled.Refresh, contentDescription = "Retry")
+ Icon(
+ imageVector = Icons.Filled.Refresh,
+ contentDescription = stringResource(R.string.action_retry),
+ )
}
}
} else {
@@ -153,7 +158,7 @@ fun ModelScreen(
fontWeight = FontWeight.Bold,
)
Text(
- text = "Slug: ${provider.slug}",
+ text = stringResource(R.string.model_label_slug, provider.slug),
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
@@ -161,7 +166,7 @@ fun ModelScreen(
if (isCurrent) {
Text(
- text = "CURRENT",
+ text = stringResource(R.string.model_status_current),
style = MaterialTheme.typography.labelMedium,
color = MaterialTheme.colorScheme.primary,
fontWeight = FontWeight.Bold,
@@ -183,7 +188,7 @@ fun ModelScreen(
AnimatedVisibility(visible = isExpanded) {
Column(modifier = Modifier.padding(top = 16.dp)) {
Text(
- text = "Available Models:",
+ text = stringResource(R.string.model_label_available),
style = MaterialTheme.typography.titleSmall,
fontWeight = FontWeight.SemiBold,
modifier = Modifier.padding(bottom = 8.dp),
@@ -192,7 +197,7 @@ fun ModelScreen(
val models = provider.models.orEmpty()
if (models.isEmpty()) {
Text(
- text = "No models reported or provider needs authentication.",
+ text = stringResource(R.string.model_no_models),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
@@ -262,7 +267,10 @@ fun ModelScreen(
if (isActive) {
Icon(
imageVector = Icons.Filled.Check,
- contentDescription = "Active Model",
+ contentDescription =
+ stringResource(
+ R.string.content_desc_active_model,
+ ),
tint = MaterialTheme.colorScheme.primary,
)
}
diff --git a/app/src/main/java/com/m57/hermescontrol/ui/sessions/SessionsScreen.kt b/app/src/main/java/com/m57/hermescontrol/ui/sessions/SessionsScreen.kt
index e5e6ad14..47662888 100644
--- a/app/src/main/java/com/m57/hermescontrol/ui/sessions/SessionsScreen.kt
+++ b/app/src/main/java/com/m57/hermescontrol/ui/sessions/SessionsScreen.kt
@@ -21,11 +21,13 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import com.m57.hermescontrol.ChatScreen
import com.m57.hermescontrol.NavigationController
+import com.m57.hermescontrol.R
import com.m57.hermescontrol.theme.LocalSpacing
import com.m57.hermescontrol.ui.common.EmptyState
import com.m57.hermescontrol.ui.common.ErrorState
@@ -48,7 +50,7 @@ fun SessionsScreen(
}
HermesScaffold(
- title = { Text("History") },
+ title = { Text(stringResource(R.string.screen_history)) },
onOpenDrawer = onOpenDrawer,
isRefreshing = state.isLoading,
onRefresh = { viewModel.loadSessions() },
@@ -61,15 +63,15 @@ fun SessionsScreen(
state.errorMessage != null -> {
ErrorState(
- message = state.errorMessage ?: "Unknown error",
+ message = state.errorMessage ?: stringResource(R.string.error_unknown),
onRetry = { viewModel.loadSessions() },
)
}
state.sessions.isEmpty() -> {
EmptyState(
- title = "No history",
- subtitle = "Previous chat sessions from Hermes will appear here.",
+ title = stringResource(R.string.history_empty_title),
+ subtitle = stringResource(R.string.history_empty_desc),
icon = Icons.Filled.History,
)
}
@@ -98,7 +100,7 @@ fun SessionsScreen(
modifier = Modifier.padding(spacing.md),
) {
Text(
- text = session.title ?: "Untitled",
+ text = session.title ?: stringResource(R.string.history_untitled),
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold,
)
@@ -107,7 +109,11 @@ fun SessionsScreen(
verticalAlignment = Alignment.CenterVertically,
) {
Text(
- text = "${session.message_count ?: 0} messages",
+ text =
+ stringResource(
+ R.string.history_message_count,
+ session.message_count ?: 0,
+ ),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
diff --git a/app/src/main/java/com/m57/hermescontrol/ui/system/SystemScreen.kt b/app/src/main/java/com/m57/hermescontrol/ui/system/SystemScreen.kt
index 2a307707..861c1bb5 100644
--- a/app/src/main/java/com/m57/hermescontrol/ui/system/SystemScreen.kt
+++ b/app/src/main/java/com/m57/hermescontrol/ui/system/SystemScreen.kt
@@ -27,8 +27,10 @@ import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.stringResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
+import com.m57.hermescontrol.R
import com.m57.hermescontrol.theme.LocalHermesStatusColors
import com.m57.hermescontrol.theme.LocalSpacing
import com.m57.hermescontrol.ui.common.EmptyState
@@ -65,7 +67,7 @@ fun SystemScreen(
}
HermesScaffold(
- title = { Text("System") },
+ title = { Text(stringResource(R.string.screen_system)) },
onOpenDrawer = onOpenDrawer,
isRefreshing = state.isLoading,
onRefresh = { viewModel.loadSystemData() },
@@ -77,15 +79,15 @@ fun SystemScreen(
state.errorMessage != null -> {
ErrorState(
- message = state.errorMessage ?: "Unknown error",
+ message = state.errorMessage ?: stringResource(R.string.error_unknown),
onRetry = { viewModel.loadSystemData() },
)
}
state.stats == null && state.doctorReport == null -> {
EmptyState(
- title = "No system data",
- subtitle = "Tap refresh to load system diagnostics.",
+ title = stringResource(R.string.system_empty_title),
+ subtitle = stringResource(R.string.system_empty_desc),
)
}
@@ -102,7 +104,7 @@ fun SystemScreen(
// Stats row
state.stats?.let { stats ->
item {
- SectionHeader(title = "Performance")
+ SectionHeader(title = stringResource(R.string.system_sec_performance))
}
item {
FlowRow(
@@ -111,7 +113,7 @@ fun SystemScreen(
) {
stats.cpuPercent?.let { cpu ->
StatCard(
- label = "CPU Usage",
+ label = stringResource(R.string.system_metric_cpu),
value = "$cpu%",
icon = Icons.Filled.Speed,
modifier = Modifier.weight(1f),
@@ -119,7 +121,7 @@ fun SystemScreen(
}
stats.memoryPercent?.let { mem ->
StatCard(
- label = "Memory",
+ label = stringResource(R.string.system_metric_memory),
value = "$mem%",
icon = Icons.Filled.Memory,
modifier = Modifier.weight(1f),
@@ -132,7 +134,7 @@ fun SystemScreen(
// Doctor diagnostics
state.doctorReport?.let { report ->
item {
- SectionHeader(title = "Doctor")
+ SectionHeader(title = stringResource(R.string.system_sec_doctor))
}
item {
Card(
@@ -158,7 +160,12 @@ fun SystemScreen(
},
)
StatusBadge(
- text = if (report.ok) "Running" else "Failed",
+ text =
+ if (report.ok) {
+ stringResource(R.string.system_status_running)
+ } else {
+ stringResource(R.string.system_status_failed)
+ },
status =
if (report.ok) {
StatusBadgeType.SUCCESS
@@ -169,10 +176,13 @@ fun SystemScreen(
}
Spacer(modifier = Modifier.height(spacing.sm))
report.pid?.let { pid ->
- InfoRow(label = "Process PID", value = pid.toString())
+ InfoRow(
+ label = stringResource(R.string.system_info_pid),
+ value = pid.toString(),
+ )
}
report.name?.let { name ->
- InfoRow(label = "Process Name", value = name)
+ InfoRow(label = stringResource(R.string.system_info_proc_name), value = name)
}
}
}
@@ -181,7 +191,7 @@ fun SystemScreen(
// Admin actions
item {
- SectionHeader(title = "Administration")
+ SectionHeader(title = stringResource(R.string.system_sec_admin))
}
item {
Card(
@@ -201,7 +211,7 @@ fun SystemScreen(
contentDescription = null,
modifier = Modifier.padding(end = spacing.xs),
)
- Text("Trigger System Backup")
+ Text(stringResource(R.string.system_action_backup))
}
}
}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index afa5e105..5c1f2527 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -195,4 +195,37 @@
Discard
Edit Skill File
Save Changes
+
+
+ No logs available
+ Log output from Hermes will appear here.
+
+
+ No system data
+ Tap refresh to load system diagnostics.
+ Performance
+ CPU Usage
+ Memory
+ Doctor
+ Running
+ Failed
+ Process PID
+ Process Name
+ Administration
+ Trigger System Backup
+
+
+ No model providers reported
+ Verify configuration or retry
+ Slug: %1$s
+ CURRENT
+ Available Models:
+ No models reported or provider needs authentication.
+ Active Model
+
+
+ No history
+ Previous chat sessions from Hermes will appear here.
+ Untitled
+ %1$d messages
\ No newline at end of file